1 Introduction

In our dataset, we have different datatypes: - Whole genome sequencing at shallow depth (sWGS) - Agilent 180K arrays - Illumina HumanCytoSNP data

These needs to be harmonised first so that they can be read into R.

1.1 sWGS

The fastq files were preprocessed with ./code/preprocessing/sWGS_pipeline_SE.snakefile, which runs bwa-mem, picard markduplicates and WisecondorX/ichorCNA. The output (bins.bed, segments.bed) from WisecondorX were further used in the downstream processing. The reference for WisecondorX was generated from an in-house dataset of healthy volunteers. More information on how to obtain a reference dataset for WisecondorX is available at https://github.com/CenterForMedicalGeneticsGhent/WisecondorX. The PoN and supporting files for ichorCNA were obtained from the ichorCNA repository (https://github.com/broadinstitute/ichorCNA).

1.2 WES

The fastq files were preprocessed with ./code/preprocessing/sWGS_pipeline_PE.snakefile, which runs bwa-mem, picard markduplicates and WisecondorX/ichorCNA.

CNVkit was run with the parameters described in cnvkit.sh on the deduplicated bam files with the paired germline sample. Target region bed files (e.g. SureSelect) was downloaded from the Agilent website. The link between the ID from germline WES and ID from tumor WES is also in the cnvkit.sh file.

1.3 Illumina HumanCytoSNP

Illumina Genomestudio 2.0 (https://www.illumina.com/techniques/microarrays/array-data-analysis-experimental-design/genomestudio.html) was used to obtain the log2ratio (Robs/Rexp) per bin from the IDAT files. The SampleSheets are available in ./resources/. The other files (.egt and .bpm are too large to host here and are available on the Illumina website (e.g. https://emea.support.illumina.com/downloads/humancytosnp-12v2-1_product_files-ns.html)

1.4 Agilent 180K array

Raw data for the Agilent 180K arrays was not available. The processed data (sample_raw.csv) was used for downstream processing. The data was processed according to the methods in https://pubmed.ncbi.nlm.nih.gov/23308108/.

1.5 Integrating the different platforms

./code/convertRaw.snakefile: converts data from obtained from WES, sWGS, Illumina HumanCytoSNP-12 or 180K array (Agilent) into a structure that allows the comparison of these different data-types, and harmonises the bin size between all data types. Also uses DNAcopy to obtain segmentations. If necessary (i.e. array data), the files are liftover to GRCh38.

Example input files are present in the ./examples/ folder.

1.6 Other scripts

./code/makeBins.sh obtain bins of choice starting from .fa.fai file, is a dependency of ./code/convertRaw.snakefile

./code/DNAcopy_segment.R: runs DNAcopy, is a dependency of ./code/convertRaw.snakefile

1.7 Load dependencies and packages

# the original CPA from Raman et al.
get.cpa <- function(seg){
   cpa <- sum(abs(seg$zscore) * (seg$end - seg$start  + 1)) / nrow(seg) * 1e-8 # per 100 Mb
   return(cpa)
}

# The modified CPA score (CPAm)
get.cpa.modified2 <- function(seg){
   cpa <- sum(abs(seg$ratio) * (seg$end - seg$start + 1)) / 1e8
   return(cpa)
}

makeCNVcomparison <- function(datadir1, datadir2, sample1, sample2, patientID, uniqueID, binsize, tumor_input, tumortype, tissueplatform){
   
   print(paste0("cfDNA sample: ", sample1))
   print(paste0("tumorDNA sample: ", sample2))
   print(paste0("binsize: ", binsize))
   
   
   bins_top <- read_tsv(paste0(datadir1, str_subset(dir(datadir1, pattern = sample1), "bins_mask")), col_types = c("fdd?d"),
                        col_names = c("chr", "start", "end", "id", "ratio"), skip = 1)
   bins_top <- bins_top %>% filter(!chr %in% c("X", "Y", "23", "24"))
   
   segs_top <- read_tsv(paste0(datadir1, str_subset(dir(datadir1, pattern = sample1), "segments_mask.bed")), col_types = c("fdddd"),
                        col_names = c("chr", "start", "end", "ratio", "zscore"))
   segs_top <- segs_top %>% filter(!chr %in% c("X", "Y", "23", "24")) %>% mutate(Sample = sample1)
   
   if (tumor_input == "array_BE" | tumor_input == "array_CZ" | tumor_input == "WES_FR" ){
      bins_bottom <-  read_tsv(paste0(datadir2,"/",sample2,"_", binsize, ".tsv"), col_types = c("fddd"),
                               col_names = c("chr", "start", "end", "ratio"))
      bins_bottom <- bins_bottom %>% filter(!chr %in% c("X", "Y", "23", "24"))
      bins_bottom$chr <- factor(bins_bottom$chr, levels = chr_order)
      
      segs_bottom <- read_tsv(paste0(datadir2,"/",sample2,"_", binsize, "_segments.tsv"), col_types = c("fddd"),
                              col_names = c("chr", "start", "end", "ratio"), skip = 1)
      
      segs_bottom <- segs_bottom %>% filter(!chr %in% c("X", "Y", "23", "24")) %>% mutate(Sample = sample2)
      segs_bottom$chr <- factor(segs_bottom$chr, levels = chr_order)
   } else if (tumor_input == "sWGS"){
      bins_bottom <-  read_tsv(paste0(datadir2, str_subset(dir(datadir2, pattern = sample2), "bins_mask")), col_types = c("fdd?d"),
                               col_names = c("chr", "start", "end", "id", "ratio"))
      bins_bottom <- bins_bottom %>% filter(!chr %in% c("X", "Y", "23", "24"))
      bins_bottom$chr <- factor(bins_bottom$chr, levels = chr_order)
      
      segs_bottom <- read_tsv(paste0(datadir2, str_subset(dir(datadir2, pattern = sample2), "segments_mask.bed")), col_types = c("fdddd"),
                              col_names = c("chr", "start", "end", "ratio", "zscore"))
      segs_bottom <- segs_bottom %>% filter(!chr %in% c("X", "Y", "23", "24")) %>% mutate(Sample = sample2)
      segs_bottom$chr <- factor(segs_bottom$chr, levels = chr_order)
   }
   
   color_top <- wes_palette("Cavalcanti1")[1]
   color_bottom <- wes_palette("Cavalcanti1")[4]
   color_abberations <- wes_palette("Cavalcanti1")[5]
   
   max.ratio_bins <- max(c(bins_top$ratio, bins_bottom$ratio), na.rm = TRUE)
   min.ratio_bins <- min(c(bins_top$ratio, bins_bottom$ratio), na.rm = TRUE)
   
   max.ratio_bins.top <- max(c(bins_top$ratio), na.rm = TRUE)
   min.ratio_bins.top <- min(c(bins_top$ratio), na.rm = TRUE)
   
   max.ratio_bins.bottom <- max(c(bins_bottom$ratio), na.rm = TRUE)
   min.ratio_bins.bottom <- min(c(bins_bottom$ratio), na.rm = TRUE)
   
   
   if (tumor_input == "sWGS"){
      cpa_top <- round(get.cpa(segs_top),4)
      cpa_bottom <- round(get.cpa(segs_bottom),4)
      cpa_top <- round(get.cpa.modified2(segs_top),4)
      cpa_bottom <- round(get.cpa.modified2(segs_bottom),4)
      cpa.calc <- "CPAm"
   } else{
      cpa_top <- round(get.cpa.modified2(segs_top),4)
      cpa_bottom <- round(get.cpa.modified2(segs_bottom),4)
      cpa.calc <- "CPAm"
   }
   
   if (tumortype == "neuroblastoma"){
      # add MYCN region
      nbl_1 <- geom_segment(data = segs_top %>% filter(chr == "2"), aes(x=15940550, xend=15947004, y=-Inf, yend=Inf), col = "grey", alpha = 0.4) 
      nbl_2 <- geom_text(data = segs_top %>% filter(chr == "2"), label = "MYCN", x=65947004, y=max.ratio_bins*0.9, angle = 90, alpha = 0.4, size = 3, color = "grey")
   } else {
      nbl_1 <- NULL
      nbl_2 <- NULL
   }
   
   ptop <- ggplot(bins_top, aes(x = start, y = ratio)) + 
      theme_bw() + 
      labs(title = paste0(patientID, " - sWGS cfDNA - ", sample1, " - ", cpa.calc,": ", cpa_top, " - ", tumortype), y = "log2(ratio)") + 
      geom_point(size = 0.3, col = color_top, alpha = 0.7) +
      lims(y = c(min.ratio_bins,max.ratio_bins))+
      theme(panel.spacing.x = unit(0, "lines"),
            panel.spacing.y = unit(0, "lines"),
            axis.title.x =  element_blank(),
            axis.text.x =  element_blank(),
            axis.ticks.x =  element_blank(),
            strip.background = element_rect(color = "white", fill = "white"),
            #   panel.border = element_rect(color = "gray", fill = NA, size = 0.3), 
            panel.grid.major = element_blank(),
            panel.grid.minor = element_blank(),
            panel.background = element_blank()) + 
      geom_hline(yintercept = 0, linetype = "dashed", col = "gray") +
      facet_wrap(~chr, strip.position = "bottom", scales ="free_x", nrow = 1) + 
      geom_segment(data = segs_top, aes(x = start, xend = end, y = ratio , yend = ratio), col = color_abberations) +
      geom_rect(data = segs_top, aes(xmin=start, xmax=end, ymin=0, ymax=ratio), fill = color_abberations, alpha = 0.4) + nbl_1 + nbl_2
   
   
   pbottom <- ggplot(bins_bottom, aes(x = start, y = ratio)) + 
      theme_bw() + 
      labs(title = paste0(patientID, " - ", tissueplatform, " tissue - ", sample2, " - ",cpa.calc, ": ", cpa_bottom, " - ", tumortype), y = "log2(ratio)") +  
      geom_point(size = 0.3, col = color_bottom, alpha = 0.7) +
      lims(y = c(min.ratio_bins,max.ratio_bins))+
      theme(panel.spacing.x = unit(0, "lines"),
            panel.spacing.y = unit(0, "lines"),
            axis.title.x =  element_blank(),
            axis.text.x =  element_blank(),
            axis.ticks.x =  element_blank(),
            strip.background = element_rect(color = "white", fill = "white"),
            panel.grid.major = element_blank(),
            panel.grid.minor = element_blank(),
            panel.background = element_blank()) + 
      geom_hline(yintercept = 0, linetype = "dashed", col = "gray") +
      facet_wrap(~chr, strip.position = "bottom", scales ="free_x", nrow = 1) +
      geom_segment(data = segs_bottom, aes(x = start, xend = end, y = ratio , yend = ratio), col = color_abberations) +
      geom_rect(data = segs_bottom, aes(xmin=start, xmax=end, ymin=0, ymax=ratio), fill = color_abberations, alpha = 0.4) + nbl_1 + nbl_2
   
   
   corplot_df_bins <- inner_join(bins_top, bins_bottom, by = c("chr", "start", "end"))
   #corplot_df <- corplot_df %>% filter(!is.na(ratio.x) & !is.na(ratio.y))
   
   corplot_df_bins <- corplot_df_bins %>%
      mutate(rM.top=rollapply(ratio.x,100, FUN=function(x) mean(x, na.rm=TRUE), fill=NA, align="right")) %>%
      mutate(rM.bottom=rollapply(ratio.y,100, FUN=function(x) mean(x, na.rm=TRUE), fill=NA, align="right")) 
   
   rollmean <- ggplot(tibble(corplot_df_bins), aes(x = start)) + 
      theme_bw() + 
      labs(y = "log2(ratio)", x = "chromosomes") +
      geom_line(aes(y=rM.bottom), col = color_bottom, alpha = 1, size = 1) +
      geom_line(aes(y=rM.top), col = color_top, alpha = 0.7, size = 1) +
      theme(panel.spacing.x = unit(0, "lines"),
            panel.spacing.y = unit(0, "lines"),
            #  axis.title.x =  element_blank(),
            axis.text.x =  element_blank(),
            axis.ticks.x =  element_blank(),
            strip.background = element_rect(color = "white", fill = "white"),
            panel.grid.major = element_blank(),
            panel.grid.minor = element_blank(),
            panel.background = element_blank()) + 
      geom_hline(yintercept = 0, linetype = "dashed", col = "gray") +
      facet_wrap(~chr, strip.position = "bottom", scales ="free_x", nrow = 1) + lims(y = c(-NA,NA))+ nbl_1
   
   max.ratio <- max(c(corplot_df_bins$ratio.x, corplot_df_bins$ratio.y), na.rm = TRUE)
   min.ratio <- min(c(corplot_df_bins$ratio.x, corplot_df_bins$ratio.y), na.rm = TRUE)
   corplot <- ggplot(corplot_df_bins, aes(x = ratio.x, y = ratio.y)) + 
      geom_point(size = 0.3, col = wes_palette("Royal1")[1]) + 
      theme_bw() +
      geom_abline(slope = 1, intercept = 0) +
      stat_cor(method = "pearson", aes(label = ..r.label..)) +
      geom_smooth(method = "lm", col = color_abberations, linetype = "dashed") +
      lims(x = c(min.ratio , max.ratio), y = c(min.ratio, max.ratio)) + 
      labs(x = "log2(ratio) cfDNA", y = "log2(ratio) tissue") +
      theme(axis.title.x = element_text(color = color_top),
            axis.title.y = element_text(color = color_bottom))
   
   R <- cor(corplot_df_bins$ratio.x, corplot_df_bins$ratio.y, use = "complete.obs", method = "pearson")
   
   CNVplot <- ggarrange(ptop, pbottom, nrow = 2, ncol = 1, align = "v", heights = c(1, 1))
   comparisons <- ggarrange(rollmean, corplot, nrow = 1, ncol = 2, widths = c(0.7, 0.3))
   
   arrangeplot <- ggarrange(CNVplot, comparisons, nrow = 2, heights = c(0.75, 0.25), widths = c(1, 0.90), align = "hv")
   ggsave(paste0(plotfolder, patientID, "_", sample1, "_", sample2, "_", binsize, ".png"), plot = arrangeplot, width = 11, height = 9, dpi = 300)
   
   df_comparison <- data.frame(UniqueID = c(uniqueID), PatientID = c(patientID), CFD_ID = c(sample1), tumorDNA_ID = c(sample2), pearsonR = c(R), cpa_cfDNA = c(cpa_top), cpa_tumorDNA = c(cpa_bottom), cpa_type = c(cpa.calc))
   return(df_comparison)
}

2 Sample annotation

The sample annotation is read from the xlsx file.

sample_annotation <- read_excel("/Users/rmvpaeme/Dropbox (speleman lab)/Basecamp/CVP/LQB pediatric patients/analysis_RVP/sample_annotation.xlsx")
sample_annotation <- sample_annotation %>% filter(cfDNA_data_available == "TRUE" & tumorDNA_data_available == "TRUE")
sample_annotation_full <- sample_annotation
sample_annotation <- sample_annotation %>% filter(is.na(filtersample))

sample_annotation$TumorGroup <- ifelse(
   sample_annotation$TumorType %in% c("Ewing sarcoma", "osteosarcoma"),
   "bone tumor",
   ifelse(
      sample_annotation$TumorType %in% c(
         "nephroblastoma",
         "malignant rhabdoid tumor of the kidney",
         "renal cell carcinoma",
         "kidney sarcoma"
      ),
      "kidney tumor",
      ifelse(
         sample_annotation$TumorType %in% c("neuroblastoma", "ganglioneuroblastoma"),
         "neuroblastoma",
         ifelse(
            sample_annotation$TumorType %in% c("rhabdomyosarcoma"),
            "rhabdomyosarcoma", "brain tumor"
         )
      )
   )
)


sample_annotation$TumorAbbrev <- sample_annotation$TumorType
sample_annotation$TumorAbbrev  <- gsub("Ewing sarcoma", "EWS", sample_annotation$TumorAbbrev)
sample_annotation$TumorAbbrev  <- gsub("osteosarcoma", "OS", sample_annotation$TumorAbbrev)
sample_annotation$TumorAbbrev  <- gsub("astrocytic pilocytoma", "ASP", sample_annotation$TumorAbbrev)
sample_annotation$TumorAbbrev  <- gsub("ependymoma", "EPA", sample_annotation$TumorAbbrev)
sample_annotation$TumorAbbrev  <- gsub("ganglioglioma", "GGA", sample_annotation$TumorAbbrev)
sample_annotation$TumorAbbrev  <- gsub("ganglioneuroblastoma", "GNA", sample_annotation$TumorAbbrev)
sample_annotation$TumorAbbrev  <- gsub("glioblastoma", "GBA", sample_annotation$TumorAbbrev)
sample_annotation$TumorAbbrev  <- gsub("hemangioblastoma", "HGA", sample_annotation$TumorAbbrev)
sample_annotation$TumorAbbrev  <- gsub("kidney sarcoma", "KS", sample_annotation$TumorAbbrev)
sample_annotation$TumorAbbrev  <- gsub("meningioma", "MGA", sample_annotation$TumorAbbrev)
sample_annotation$TumorAbbrev  <- gsub("malignant rhabdoid tumor of the kidney", "MRT", sample_annotation$TumorAbbrev)
sample_annotation$TumorAbbrev  <- gsub("nephroblastoma", "NFB", sample_annotation$TumorAbbrev)
sample_annotation$TumorAbbrev  <- gsub("neuroblastoma", "NBL", sample_annotation$TumorAbbrev)
sample_annotation$TumorAbbrev  <- gsub("renal cell carcinoma", "RCC", sample_annotation$TumorAbbrev)
sample_annotation$TumorAbbrev  <- gsub("rhabdomyosarcoma", "RMS", sample_annotation$TumorAbbrev)
sample_annotation$TumorAbbrev  <- gsub("medulloblastoma", "MBL", sample_annotation$TumorAbbrev)

sample_annotation$cfDNA_HMW_ratio <- as.numeric(sample_annotation$cfDNA_prct_conc)/as.numeric(sample_annotation$HMW_prct_conc)
sample_annotation$cfDNA_HMW_ratio <- as.numeric(sample_annotation$cfDNA_HMW_ratio)


sample_annotation$quality_score <- ifelse(sample_annotation$cfDNA_HMW_ratio < 1, "low",
                                          ifelse(sample_annotation$cfDNA_HMW_ratio < 5 & sample_annotation$cfDNA_HMW_ratio > 1, "medium", "high"))

sample_annotation$cfDNA_prct <- as.numeric(sample_annotation$cfDNA_prct_conc)/(as.numeric(sample_annotation$HMW_prct_conc)+as.numeric(sample_annotation$cfDNA_prct_conc))
sample_annotation$cfDNA_HMW_ratio <- as.numeric(sample_annotation$cfDNA_HMW_ratio)


tumorSamples <- sample_annotation %>% select(UniqueID, PatientID, tumorDNA_ID, TumorType,tumorDNA_assay,tumorDNA_assay_detail, tumorDNA_biomaterial, TumorGroup,cfDNA_HMW_ratio )
colnames(tumorSamples) <- c("UniqueID", "PatientID",  "SampleID", "TumorType", "assay", "assayDetail", "source", "TumorGroup", "cfDNA_HMW_ratio")
tumorSamples$biomaterial <- "tumor DNA"

cfDNASamples <-  sample_annotation %>% select(UniqueID, PatientID, CFD_ID, TumorType,tumorDNA_assay,tumorDNA_assay_detail, CFD_biomaterial, TumorGroup, cfDNA_HMW_ratio) 
colnames(cfDNASamples) <- c("UniqueID", "PatientID",  "SampleID", "TumorType", "assay", "assayDetail", "source", "TumorGroup", "cfDNA_HMW_ratio")
cfDNASamples$assay <- "sWGS"
cfDNASamples$assayDetail <- "sWGS"
cfDNASamples$biomaterial <- "cfDNA"

sample_annotation_long <- bind_rows(tumorSamples, cfDNASamples)

4 Reading in all data

While reading in the data, the loop makes a comparative figure for every comparison in sample_annotation, for example:

comparison

comparison

if (!file.exists("./data/compareAll.tsv")){
   cfDNAvsTissue <- data.frame()
   #sample_annotation <- sample_annotation  %>% filter(SampleOrigin == "MH")
   for (row in 1:nrow(sample_annotation)){
      sample1 <- sample_annotation[row,]$CFD_ID
      sample2 <- sample_annotation[row,]$tumorDNA_ID
      patientID <-  sample_annotation[row,]$PatientID
      uniqueID <-  sample_annotation[row,]$UniqueID
      tissueplatform <- sample_annotation[row,]$tumorDNA_assay_detail
      tumortype <- sample_annotation[row,]$TumorType
      datadir1 <- datadir_sWGS_cfDNA
      if (sample_annotation[row,]$tumorDNA_assay == "array_BE"){
         input_tumor = "array_BE"
         datadir2 <-  datadir_arrayBE
      } else if (sample_annotation[row,]$tumorDNA_assay == "array_CZ"){
         input_tumor = "array_CZ"
         datadir2 <-  datadir_arrayCZ
      } else if (sample_annotation[row,]$tumorDNA_assay == "WES_FR"){
         input_tumor = "WES_FR"
         datadir2 <-  datadir_WES
      } else if (sample_annotation[row,]$tumorDNA_assay == "sWGS"){
         input_tumor = "sWGS"
         datadir2 <-  datadir_sWGS_tissue
      }
      if (length(dir(datadir2, pattern = sample2) > 0  | length(dir(datadir1, pattern = sample1) > 0))) {
         tmp <- makeCNVcomparison(datadir1, datadir2, sample1, sample2, patientID, uniqueID, "200kb", input_tumor, tumortype,tissueplatform)
         cfDNAvsTissue <- rbind(cfDNAvsTissue, tmp)
      }
      print(paste0("Processed: ", row, "/", nrow(sample_annotation)))
   }
   write_tsv(cfDNAvsTissue, "./data/compareAll.tsv")
} else {
   cfDNAvsTissue  <- read_tsv("./data/compareAll.tsv")
}

a <- cfDNAvsTissue %>% select(PatientID,  UniqueID, CFD_ID, cpa_cfDNA, pearsonR)
colnames(a) <- c("PatientID", "UniqueID","SampleID", "CPAm", "pearsonR")
a$biomaterial <- "cfDNA"

b <- cfDNAvsTissue %>% select(PatientID, UniqueID, tumorDNA_ID, cpa_tumorDNA, pearsonR )
colnames(b) <-  c("PatientID", "UniqueID","SampleID", "CPAm", "pearsonR")
b$biomaterial <- "tumor DNA"

a <- rbind(a,b)
sample_annotation_long <- left_join(sample_annotation_long, a)
a <- NULL
b <- NULL


cfDNAvsTissue <- merge(sample_annotation, cfDNAvsTissue, by = c("PatientID", "UniqueID", "PatientID", "CFD_ID", "tumorDNA_ID"))


normal_CPA <- read_csv("./data/sWGS_healthy/CPA_all.csv") %>% dplyr::select(-CPAm) %>% melt() 
colnames(normal_CPA) <- c("CFD_ID","cpa_type", "cpa_cfDNA")

normal_CPAm <- read_csv("./data/sWGS_healthy/CPA_all.csv") %>% dplyr::select(-CPA) %>% melt() 
colnames(normal_CPAm) <- c("CFD_ID","cpa_type", "cpa_cfDNA")
normal_CPAm$cpa_tumorDNA <- normal_CPA$cpa_cfDNA
normal_CPAm$TumorType <- "healthy"
normal_CPAm$CFD_biomaterial <- "plasma"
normal_CPAm$SampleOrigin <- "UZG"
normal_CPAm$cfDNA_HMW_ratio <- 0
cfDNAvsTissue_withHealthy <- bind_rows(cfDNAvsTissue, normal_CPAm)

5 Calculation of the 1% FDR for CPAm/CPA values

A normal distribution is fitted to the CPAm values, and based on the mean and SD, the qnorm(.99) is determined to obtain the 1% FDR ratio.

The 1% FDR for CPAm is 0.3549618 and the 1% FDR for CPA is 1.5344485.

library(geiger)
binsize = "200kb"

makeLog2comparison <- function(datadir1, datadir2, sample1, sample2, patientID){
   
   print(paste0("cfDNA sample: ", sample1))
   print(paste0("tumorDNA sample: ", sample2))
   print(paste0("binsize: ", binsize))
   
   
   tmp_A <- read_tsv(paste0(datadir1, str_subset(dir(datadir1, pattern = sample1), "segments_per_200kb_mask.tsv")), col_types = c("fddd"),
                     col_names = c("chr", "start", "end", "ratio_cfDNA"), skip = 1)
   tmp_A <- tmp_A %>% filter(!chr %in% c("X", "Y", "23", "24")) 
   
   
   segs_A <- read_tsv(paste0(datadir1, str_subset(dir(datadir1, pattern = sample1), "segments_mask.bed")), col_types = c("fdddd"),
                      col_names = c("chr", "start", "end", "ratio", "zscore"))
   segs_A <- segs_A %>% filter(!chr %in% c("X", "Y", "23", "24"))
   
   tmp_B <- read_tsv(paste0(datadir2, str_subset(dir(datadir2, pattern = sample2), "segments_per_200kb_mask.tsv")), col_types = c("fddd"),
                     col_names = c("chr", "start", "end", "ratio_tumor"), skip = 1)
   tmp_B <- tmp_B %>% filter(!chr %in% c("X", "Y", "23", "24")) 
   
   if (tumor_input == "array_BE" | tumor_input == "array_CZ" | tumor_input == "WES_FR"){
      segs_B <- read_tsv(paste0(datadir2,"/",sample2,"_", binsize, "_segments.tsv"), col_types = c("fddd"),
                         col_names = c("chr", "start", "end", "ratio"), skip = 1)
      
      segs_B <- segs_B %>% filter(!chr %in% c("X", "Y", "23", "24")) 
   } else if (tumor_input == "sWGS"){
      segs_B <- read_tsv(paste0(datadir2, str_subset(dir(datadir2, pattern = sample2), "segments_mask.bed")), col_types = c("fdddd"),
                         col_names = c("chr", "start", "end", "ratio", "zscore"))
      segs_B <- segs_B %>% filter(!chr %in% c("X", "Y", "23", "24")) 
   }
   # 
   # segs_B <- read_tsv(paste0(datadir2,"/",sample2,"_", binsize, "_segments.tsv"), col_types = c("fddd"),
   #                      col_names = c("chr", "start", "end", "ratio"), skip = 1)
   # 
   # segs_B <- segs_B %>% filter(!chr %in% c("X", "Y", "23", "24")) 
   
   tmp <- inner_join(tmp_A, tmp_B)
   tmp$abslog2diffPerBin <- abs(tmp$ratio_tumor - tmp$ratio_cfDNA)
   segdiff <- nrow(segs_B) - nrow(segs_A)
   
   meanDiffPerBin <- mean(tmp$abslog2diffPerBin*segdiff)
   cumulDiffPerBin <- sum(tmp$abslog2diffPerBin*segdiff)
   data.frame(cfDNA_ID = sample1, tumorDNA_ID = sample2, mean_abs_diff_log2 = meanDiffPerBin, cumulDiffPerBin = cumulDiffPerBin)
}

makeBinsComparison <- function(datadir1, datadir2, sample1, sample2, patientID){
   
   bins_top <- read_tsv(paste0(datadir1, str_subset(dir(datadir1, pattern = sample1), "bins_mask")), col_types = c("fdd?d"),
                        col_names = c("chr", "start", "end", "id", "ratio"), skip = 1)
   bins_top <- bins_top %>% filter(!chr %in% c("X", "Y", "23", "24"))%>% mutate(SampleID = sample1)
   
   if (tumor_input == "array_BE" | tumor_input == "array_CZ" | tumor_input == "WES_FR" ){
      bins_bottom <-  read_tsv(paste0(datadir2,"/",sample2,"_", binsize, ".tsv"), col_types = c("fddd"),
                               col_names = c("chr", "start", "end", "ratio"))
      bins_bottom <- bins_bottom %>% filter(!chr %in% c("X", "Y", "23", "24")) %>% mutate(SampleID = sample2)
      bins_bottom$chr <- factor(bins_bottom$chr, levels = chr_order)
      
   } else if (tumor_input == "sWGS"){
      bins_bottom <-  read_tsv(paste0(datadir2, str_subset(dir(datadir2, pattern = sample2), "bins_mask")), col_types = c("fdd?d"),
                               col_names = c("chr", "start", "end", "id", "ratio"))
      bins_bottom <- bins_bottom %>% filter(!chr %in% c("X", "Y", "23", "24"))%>% mutate(SampleID = sample2) %>% select(-id)
      bins_bottom$chr <- factor(bins_bottom$chr, levels = chr_order)
   }
   
   
   corplot_df_bins <- full_join(bins_top, bins_bottom, by = c("chr", "start", "end")) %>% select(-chr, -start, -end)
   colnames(corplot_df_bins) <- c("id", "L2R_cfDNA", "CFD_ID", "L2R_tumorDNA", "tumorDNA_ID")
   corplot_df_bins$PatientID <- patientID
   corplot_df_bins
   
}


if (!file.exists("./data/alldiffs.tsv")){
   alldiffs <- data.frame()
   L2Rcomparison <- data.frame()
   for (row in 1:nrow(sample_annotation)){
      sample1 <- sample_annotation[row,]$CFD_ID
      sample2 <- sample_annotation[row,]$tumorDNA_ID
      patientID <-  sample_annotation[row,]$PatientID
      tissueplatform <- sample_annotation[row,]$tumorDNA_assay_detail
      tumortype <- sample_annotation[row,]$TumorType
      datadir1 <- datadir_sWGS_cfDNA
      if (sample_annotation[row,]$tumorDNA_assay == "array_BE"){
         tumor_input = "array_BE"
         datadir2 <-  datadir_arrayBE
      } else if (sample_annotation[row,]$tumorDNA_assay == "array_CZ"){
         tumor_input = "array_CZ"
         datadir2 <-  datadir_arrayCZ
      } else if (sample_annotation[row,]$tumorDNA_assay == "WES_FR"){
         tumor_input = "WES_FR"
         datadir2 <-  datadir_WES
      } else if (sample_annotation[row,]$tumorDNA_assay == "sWGS"){
         tumor_input = "sWGS"
         datadir2 <-  datadir_sWGS_tissue
      }
      if (length(dir(datadir2, pattern = sample2) > 0  | length(dir(datadir1, pattern = sample1) > 0))) {
         tmp <- makeLog2comparison(datadir1, datadir2, sample1, sample2, patientID)
         tmp_L2R <- makeBinsComparison(datadir1, datadir2, sample1, sample2, patientID)
         alldiffs <- rbind(alldiffs, tmp)
         L2Rcomparison <- rbind(L2Rcomparison, tmp_L2R)
      }
      print(paste0("Processed: ", row, "/", nrow(sample_annotation)))
   }
   write_tsv(alldiffs, "./data/alldiffs.tsv")
   write_tsv(L2Rcomparison, "./data/L2R.tsv")
} else {
   alldiffs  <- read_tsv("./data/alldiffs.tsv")
   L2Rcomparison <- read_tsv("./data/L2R.tsv")
}

cfDNAvsTissue <- left_join(cfDNAvsTissue, alldiffs, by = c("CFD_ID" = "cfDNA_ID", "tumorDNA_ID" = "tumorDNA_ID"))
L2Rcomparison <- left_join(cfDNAvsTissue, L2Rcomparison, by = c("CFD_ID" = "CFD_ID", "tumorDNA_ID" = "tumorDNA_ID", "PatientID" = "PatientID"))
if (!file.exists("./data/merged_segments.tsv")){
   read_segments <- function(datadir){
      files<-list.files(c(datadir),recursive=TRUE)
      files<-files[grep("egments_per_[0-9]+kb_mask", files)]
      tmp_heatmap <- data.frame()
      for(i in 1:length(files)){
         name_sample <- gsub("_segments_per_[0-9]+kb_mask.tsv", "", files[i])
         print(name_sample)
         tmp <-  read_tsv(paste0(datadir,files[i]), col_types = c("fddd"),
                          col_names = c("chr", "start", "end", "ratio"), skip = 1)
         
         colnames(tmp)<- c("chr", "start", "end", "ratio")
         tmp <- tmp %>% filter(!chr %in% c("X", "Y", "23", "24"))
         tmp$SampleID <- name_sample
         tmp$meanLog2 <- get.cpa.modified2(tmp)
         if (nrow(tmp_heatmap) == 0){
            tmp_heatmap <- tmp
         } else {
            tmp_heatmap <- rbind(tmp_heatmap, tmp)
         }
      }
      return(tmp_heatmap)
   }
   df_heatmap_init <- data.frame()
   df_heatmap_init <- rbind(df_heatmap_init, read_segments(datadir_sWGS_cfDNA))
   df_heatmap_init <- rbind(df_heatmap_init, read_segments(datadir_WES))
   df_heatmap_init <- rbind(df_heatmap_init, read_segments(datadir_sWGS_tissue))
   df_heatmap_init <- rbind(df_heatmap_init, read_segments(datadir_arrayCZ))
   df_heatmap_init <- rbind(df_heatmap_init, read_segments(datadir_arrayBE))
   
   df_heatmap_healthy <- data.frame()
   df_heatmap_healthy <- rbind(df_heatmap_healthy, read_segments(datadir_healthy))
   write_tsv(df_heatmap_init, "./data/merged_segments.tsv")
   write_tsv(df_heatmap_healthy, "./data/merged_segments_healthy.tsv")
} else {
   df_heatmap_init <- read_tsv("./data/merged_segments.tsv")
   df_heatmap_healthy <- read_tsv("./data/merged_segments_healthy.tsv")
}

df_heatmap_init$SampleID <- gsub("_.*", "", df_heatmap_init$SampleID)
df_heatmap_init <- df_heatmap_init 

a <- df_heatmap_init %>% distinct(meanLog2, SampleID)
cfDNAvsTissue <- left_join(cfDNAvsTissue, a, by = c("CFD_ID" = "SampleID"))
cfDNAvsTissue <- left_join(cfDNAvsTissue, a, by = c("tumorDNA_ID" = "SampleID"))
cfDNAvsTissue$deltaLog2 <- abs(cfDNAvsTissue$meanLog2.x - cfDNAvsTissue$meanLog2.y)
a <- NULL

6 Difference plot between cfDNA and tumor DNA

tumor = "nephroblastoma"
makeBarTumorvscfDNA <- function(tumor){
   barPlot <- df_heatmap_init
   sampleFilt_a <- sample_annotation_long %>% filter(cfDNA_HMW_ratio > 5) %>% filter(TumorType == tumor & biomaterial == "cfDNA") %>% pull(SampleID)
   barPlot_a <- barPlot %>% filter(SampleID %in% sampleFilt_a)
   barPlot_a <- barPlot_a %>% group_by(chr, start) %>%
      summarise(mean = mean(ratio, na.rm = TRUE),
                sd = sd(ratio, na.rm = TRUE),
                n = n()) %>%
      mutate(se = sd / sqrt(n),
             lower.ci = mean - qt(1 - (0.05 / 2), n - 1) * se,
             upper.ci = mean + qt(1 - (0.05 / 2), n - 1) * se) 
   barPlot_a$biomaterial <- "cfDNA"
   
   sampleFilt_b <- sample_annotation_long %>% filter(cfDNA_HMW_ratio > 1) %>% filter(TumorType == tumor & biomaterial == "tumor DNA") %>% pull(SampleID)
   barPlot_b <- barPlot %>% filter(SampleID %in% sampleFilt_b)
   barPlot_b <- barPlot_b %>% group_by(chr, start) %>%
      summarise(mean = mean(ratio, na.rm = TRUE),
                sd = sd(ratio, na.rm = TRUE),
                n = n()) %>%
      mutate(se = sd / sqrt(n),
             lower.ci = mean - qt(1 - (0.05 / 2), n - 1) * se,
             upper.ci = mean + qt(1 - (0.05 / 2), n - 1) * se) 
   barPlot_b$biomaterial <- "tumor DNA"
   
   
   ggplot() + 
      theme_bw() + 
      # labs(title = paste0(patientID, " - ", tissueplatform, " tissue - ", sample2, " - ",cpa.calc, ": ", cpa_bottom, " - ", tumortype), y = "log2(ratio)") +
      geom_bar(data = barPlot_a, aes(x = start, y = mean, col = biomaterial, fill = biomaterial), stat = "identity", position = "dodge", alpha = 1, size = 0) +
      geom_bar(data = barPlot_b, aes(x = start, y = mean, col = biomaterial, fill = biomaterial), stat = "identity", position = "dodge", alpha = 0.5, size = 0) +
      lims(y = c(-.6,.6))+ 
      labs(title = paste0(tumor, " (n = ", length(sampleFilt_b),")"), y = "mean of log2(ratio) across all samples")+
      theme(panel.spacing.x = unit(0, "lines"),
            panel.spacing.y = unit(0, "lines"),
            axis.title.x =  element_blank(),
            axis.text.x =  element_blank(),
            axis.ticks.x =  element_blank(),
            strip.background = element_rect(color = "white", fill = "white"),
            panel.grid.major = element_blank(),
            panel.grid.minor = element_blank(),
            panel.background = element_blank()) + 
      geom_hline(yintercept = 0, linetype = "dashed", col = "gray") +
      facet_wrap(~chr, strip.position = "bottom", scales ="free_x", nrow = 1)}

p1 <- makeBarTumorvscfDNA("neuroblastoma")
p2 <- makeBarTumorvscfDNA("nephroblastoma")
p3 <- makeBarTumorvscfDNA("osteosarcoma")
p4 <- makeBarTumorvscfDNA("rhabdomyosarcoma")
p5 <- makeBarTumorvscfDNA("Ewing sarcoma")

7 Sequencing quality control metrics

7.2 Duplicate percentage

9 Comparison of cfDNA vs tissue

9.1 Crosstable of cfDNA and tumor CNAs

9.2 Correlation of CPAm and CPA

Where possible (shallow WGS samples, n = 82), the correlation between the CPA and CPAm was calculated and yielded a Pearson R of 0.74 and a spearman rho of 0.86. The CPAm threshold of copy number neutral (“normal” or “flat”) at the 1% false discovery level in cfDNA was calculated on the cohort of healthy controls (individuals above 18 years old with no cancer diagnosis in their past medical history) from Raman et al. and was found to be 0.354. With this threshold, there are 4/82 cfDNA samples that were labeled discordant, i.e., copy number neutral with CPA and copy number aberrations with CPAm. Upon manual inspection, 3 out of these 4 samples contain visible CNAs, while 1 out of 4 samples is copy number neutral.

The samples that were discordant between CPA (1% FDR = 1.5344485) and CPAm (1% FDR = 0.3549618) are:

9.5 CPA cfDNA vs Pearson R ~ cfDNA/HMW ratio

9.6 Tumor types in dataset

ggsave("./plots/tumorsInDataset.png", plot = ggplot2::last_plot(), dpi = 300, width = 10, height = 6)
ggsave("./plots/tumorsInDataset.pdf", plot = ggplot2::last_plot(), dpi = 300, width = 10, height = 6)

cfDNAvsTissue_select <- cfDNAvsTissue_withHealthy %>% filter(TumorType %in% c("neuroblastoma", "nephroblastoma", "osteosarcoma", "rhabdomyosarcoma", "Ewing sarcoma", "healthy") & (cpa_type == "CPAm")) %>% filter(as.numeric(cfDNA_HMW_ratio) >= 0)

ridgeplot_cfDNA_per_tumor <- ggplot(
   cfDNAvsTissue_select %>% filter(TumorType != "healthy"), 
   aes(y = TumorType, x = cpa_cfDNA, fill = TumorType)) +
   geom_density_ridges(show.legend = FALSE, scale = 0.8, panel_scaling = FALSE,
                       point_alpha = 0.7, alpha = .2, point_shape = 1,
                       aes(point_color = TumorType,
                           point_fill = TumorType,
                           point_size = as.numeric(cfDNA_HMW_ratio)), 
                       jittered_points = TRUE, position = "raincloud") +
   theme_bw() + 
   labs(point_size = "cfDNA/HMW ratio", fill = "tumor", point_fill = "tumor", point_color = "tumor", x = "CPAm cfDNA", y = "tumor") + 
   geom_boxplot(alpha = 0.4, width = 0.2, show.legend = FALSE, outlier.shape = NA) + 
   theme(legend.position="right")+
   geom_vline(data=cfDNAvsTissue %>% filter(cpa_type == "CPAm"), alpha = 0.6, aes(xintercept = FDR_CPAm), linetype = "dashed")+
   annotate("rect",xmin = 0, xmax = FDR_CPAm, ymin = -Inf, ymax = Inf, alpha=0.3, fill="grey")  + lims(x = c(0,NA))


ridgeplot_tissueDNA_per_tumor <- ggplot(
   cfDNAvsTissue_select %>% filter(TumorType != "healthy"), 
   aes(y = TumorType, x = cpa_tumorDNA, fill = TumorType)) +
   geom_density_ridges(show.legend = FALSE, scale = 0.8, panel_scaling = FALSE,
                       point_alpha = 0.7, alpha = .2, point_shape = 1,
                       aes(point_color = TumorType, point_fill = TumorType), jittered_points = TRUE, position = "raincloud") +
   theme_bw() + 
   labs(y="", point_size = "cfDNA/HMW ratio", fill = "tumor", point_fill = "tumor", point_color = "tumor", x = "CPAm tumorDNA", y = "tumor") + 
   geom_boxplot(alpha = 0.4, width = 0.2, show.legend = FALSE, outlier.shape = NA) + 
   theme(legend.position="right") + theme(axis.text.y = element_blank())

9.7 Impact on neuroblastoma risk stratification

9.7.1 All samples

cfDNA tumor Total
MYCN neutral MYCN gain
MYCN neutral 56
100 %
100 %
80 %
0
0 %
0 %
0 %
56
100 %
80 %
80 %
MYCN gain 0
0 %
0 %
0 %
14
100 %
100 %
20 %
14
100 %
20 %
20 %
Total 56
80 %
100 %
80 %
14
20 %
100 %
20 %
70
100 %
100 %
100 %
χ2=63.890 · df=1 · φ=1.000 · Fisher’s p=0.000

9.7.2 cfDNA/HMW ratio above 1

cfDNA tumor Total
MYCN neutral MYCN gain
MYCN neutral 30
100 %
100 %
73.2 %
0
0 %
0 %
0 %
30
100 %
73.2 %
73.2 %
MYCN gain 0
0 %
0 %
0 %
11
100 %
100 %
26.8 %
11
100 %
26.8 %
26.8 %
Total 30
73.2 %
100 %
73.2 %
11
26.8 %
100 %
26.8 %
41
100 %
100 %
100 %
χ2=36.064 · df=1 · φ=1.000 · Fisher’s p=0.000

9.8 Impact on 1q gain in nephroblastoma

9.8.1 All samples

cfDNA tumor Total
1q neutral 1q gain
1q neutral 14
73.7 %
87.5 %
58.3 %
5
26.3 %
62.5 %
20.8 %
19
100 %
79.2 %
79.1 %
1q gain 2
40 %
12.5 %
8.3 %
3
60 %
37.5 %
12.5 %
5
100 %
20.8 %
20.8 %
Total 16
66.7 %
100 %
66.7 %
8
33.3 %
100 %
33.3 %
24
100 %
100 %
100 %
χ2=0.789 · df=1 · φ=0.290 · Fisher’s p=0.289

9.8.2 cfDNA/HMW ratio above 1

cfDNA tumor Total
1q neutral 1q gain
1q neutral 10
71.4 %
83.3 %
55.6 %
4
28.6 %
66.7 %
22.2 %
14
100 %
77.8 %
77.8 %
1q gain 2
50 %
16.7 %
11.1 %
2
50 %
33.3 %
11.1 %
4
100 %
22.2 %
22.2 %
Total 12
66.7 %
100 %
66.7 %
6
33.3 %
100 %
33.3 %
18
100 %
100 %
100 %
χ2=0.040 · df=1 · φ=0.189 · Fisher’s p=0.569

10 Generalized Additive Modelling

10.1 Data cleaning

  • Number of total observations 1664725
  • NUmber of observations after removing all NAs: 1227545

10.3 Summary

## NULL

10.4 Visualisation of assumptions

## 
## Method: fREML   Optimizer: perf chol
## $grad
## [1] 0.00000006012634
## 
## $hess
##          [,1]
## [1,] 40.55676
## 
## Model rank =  103 / 103 
## 
## Basis dimension (k) checking results. Low p-value (k-index<1) may
## indicate that k is too low, especially if edf is close to k'.
## 
##                k'  edf k-index p-value
## s(PatientID) 89.0 81.7      NA      NA

10.5 Regression coefficient table

  L2R_cfDNA
Predictors Estimates CI p
(Intercept) -0.0025 -0.0136 – 0.0086 0.656
cfDNA_HMW_ratio_log10 0.0035 -0.0006 – 0.0076 0.097
L2R_tumorDNA 0.0043 0.0009 – 0.0077 0.012
L2R_tumorDNA:cfDNA_HMW_ratio_log10 0.1461 0.1446 – 0.1477 <0.001
L2R_tumorDNA:metastaticTRUE 0.1561 0.1529 – 0.1594 <0.001
L2R_tumorDNA:TumorTypenephroblastoma 0.3218 0.3169 – 0.3267 <0.001
L2R_tumorDNA:TumorTypeneuroblastoma 0.2693 0.2650 – 0.2737 <0.001
L2R_tumorDNA:TumorTypeosteosarcoma 0.1377 0.1337 – 0.1417 <0.001
L2R_tumorDNA:TumorTyperhabdomyosarcoma 0.2619 0.2569 – 0.2669 <0.001
Ewingsarcoma Reference
nephroblastoma -0.0021 -0.0153 – 0.0111 0.752
neuroblastoma 0.0024 -0.0109 – 0.0156 0.726
osteosarcoma 0.0029 -0.0126 – 0.0185 0.713
rhabdomyosarcoma 0.0036 -0.0114 – 0.0185 0.638
FALSE Reference
TRUE 0.0029 -0.0057 – 0.0115 0.512
patient_001 Reference
patient_002 Reference
patient_003 Reference
patient_004 Reference
patient_005 Reference
patient_006 Reference
patient_007 Reference
patient_008 Reference
patient_009 Reference
patient_010 Reference
patient_011 Reference
patient_013 Reference
patient_014 Reference
patient_015 Reference
patient_016 Reference
patient_017 Reference
patient_022 Reference
patient_023 Reference
patient_025 Reference
patient_027 Reference
patient_028 Reference
patient_029 Reference
patient_031 Reference
patient_032 Reference
patient_033 Reference
patient_034 Reference
patient_035 Reference
patient_036 Reference
patient_037 Reference
patient_038 Reference
patient_039 Reference
patient_041 Reference
patient_043 Reference
patient_053 Reference
patient_054 Reference
patient_055 Reference
patient_056 Reference
patient_057 Reference
patient_058 Reference
patient_060 Reference
patient_072 Reference
patient_073 Reference
patient_074 Reference
patient_075 Reference
patient_077 Reference
patient_078 Reference
patient_079 Reference
patient_080 Reference
patient_082 Reference
patient_083 Reference
patient_084 Reference
patient_105 Reference
patient_108 Reference
patient_110 Reference
patient_111 Reference
patient_116 Reference
patient_117 Reference
patient_118 Reference
patient_121 Reference
patient_122 Reference
patient_127 Reference
patient_128 Reference
patient_131 Reference
patient_135 Reference
patient_136 Reference
patient_137 Reference
patient_138 Reference
patient_139 Reference
patient_146 Reference
patient_152 Reference
patient_159 Reference
patient_168 Reference
patient_170 Reference
patient_180 Reference
patient_183 Reference
patient_185 Reference
patient_186 Reference
patient_188 Reference
patient_189 Reference
patient_191 Reference
patient_192 Reference
patient_194 Reference
patient_202 Reference
patient_203 Reference
s(PatientID) 81.7364 <0.001
patient_204 Reference
patient_211 Reference
patient_212 Reference
patient_217 Reference
patient_219 Reference
Observations 1131209
R2 0.356

11 Heatmap

df_heatmap_init = df_heatmap_init %>% select(-c(meanLog2))

# params to test function with
#sample_select <- c("osteosarcoma", "Ewing sarcoma", "rhabdomyosarcoma")
#width_px = 1200
#height_px = 1800
#sample_select <- "neuroblastoma"

makeHeatmap <- function(df_heatmap_init, sample_select, width_px, height_px, arrangehm = "tumor"){
   #df_heatmap = df_heatmap_init %>% filter(str_detect(SampleID, neuroblastoma))
   df_heatmap <- df_heatmap_init
   df_heatmap$bin <- paste0(as.character(df_heatmap$chr), ":", as.character(df_heatmap$start), "-", as.character(df_heatmap$end))
   
   # find cause of duplicates
   df_heatmap <- df_heatmap %>% select(-c(chr, start, end)) %>% group_by(SampleID) %>% distinct(bin, .keep_all = TRUE) %>% ungroup() %>% spread(key = c(bin), value = ratio)
   df_heatmap <- df_heatmap %>% 
      select(where(~!any(is.na(.))))
   #df_heatmap <- df_heatmap %>% distinct(SampleID, .keep_all = TRUE)
   
   colnames_hm <- paste0(gsub(":.*", "", colnames(df_heatmap[,2:ncol(df_heatmap)])))
   colnames_hm <- factor(colnames_hm, levels = chr_order)
   rownames_hm <- df_heatmap$SampleID
   
   
   sampleTypes <- sample_annotation_long %>% filter(SampleID  %in% rownames_hm)
   
   sampleTypes <- sampleTypes %>% dplyr::arrange(PatientID)
   
   df_heatmap <- inner_join(sampleTypes, df_heatmap)
   if (arrangehm == "pearsonR"){
      df_heatmap <- df_heatmap %>% dplyr::arrange(desc(pearsonR),PatientID, TumorType)
   }else{
      df_heatmap <- df_heatmap %>% dplyr::arrange(PatientID, TumorType)
   }
   df_heatmap <- df_heatmap %>% distinct(SampleID, `1:100400001-100600000`, 
                                         `1:107200001-107400000`,
                                         `1:113000001-113200000`,
                                         `1:117800001-118000000`, .keep_all = TRUE)
   if (arrangehm == "pearsonR"){
      df_heatmap <- df_heatmap %>% filter(PatientID %in% sample_select)
   } else{
      df_heatmap <- df_heatmap %>% filter(TumorType %in% sample_select)
   }
   
   df_heatmap$pearsonR <- round(df_heatmap$pearsonR, 2)
   #df_heatmap$pearsonR <- ifelse(df_heatmap$biomaterial == "cfDNA", NA, df_heatmap$pearsonR)
   #    cbind(sample_annotation$sWGS, sample_annotation$TumorType, rep("sWGS", nrow(sample_annotation))),
   #    cbind(sample_annotation$array, sample_annotation$TumorType, rep("array", nrow(sample_annotation)))
   # ))
   # colnames(sampleTypes) <- c("SampleID", "tumor", "type")
   
   ht_opt(
      legend_title_gp = gpar(fontsize = 20, fontface = "bold"),
      legend_labels_gp = gpar(fontsize = 20),
      ROW_ANNO_PADDING = unit(8,"mm")
   )
   
   tumor_col <- colorRampPalette(colors = brewer.pal(12, "Paired")) (length(levels(as.factor(df_heatmap$TumorType))))
   names(tumor_col) <- levels(as.factor(df_heatmap$TumorType))
   
   platform_col <- colorRampPalette(colors = brewer.pal(9, "Set1")) (length(levels(as.factor(df_heatmap$assayDetail))))
   names(platform_col) <- levels(as.factor(df_heatmap$assayDetail))
   
   biomat_col <- colorRampPalette(colors = brewer.pal(3, "Set3")) (length(levels(as.factor(df_heatmap$biomaterial))))
   names(biomat_col) <- levels(as.factor(df_heatmap$biomaterial))
   
   source_col <- colorRampPalette(colors = brewer.pal(5, "Set2")) (length(levels(as.factor(df_heatmap$source))))
   names(source_col) <- levels(as.factor(df_heatmap$source))
   
   pearsonR_col <- colorRamp2(c(-0.1, 1), colors = c("white", "purple"))
   
   ha = HeatmapAnnotation(
      CPAm = anno_barplot(df_heatmap$CPAm, gp = gpar(fill = 2, col = 2)),
      pearsonR = df_heatmap$pearsonR,
      platform = df_heatmap$assayDetail,
      col = list(platform = platform_col, biomaterial = biomat_col, tumor = tumor_col, source = source_col),
      biomaterial = df_heatmap$biomaterial,
      tumor = df_heatmap$TumorType,
      source  = df_heatmap$source,
      annotation_name_side = "bottom", which = "row", show_legend = TRUE,
      width = unit(6, "cm"),
      gap = unit(0.5, "mm"),
      show_annotation_name = TRUE,
      simple_anno_size = unit(0.8, "cm"),
      annotation_legend_param = 
         list(
            platform = list(
               title = "platform"
            ),
            biomaterial = list(
               title = "biomaterial"
            ),
            tumor = list(
               title = "tumor", 
               ncol = 1
            ),
            source = list(
               title = "source", 
               ncol = 1
            )
         ))
   
   loss <- wes_palette("Zissou1")[1]
   gain <- wes_palette("Zissou1")[5]
   neutral <- "#F1F1F1"
   hm_q <- quantile(df_heatmap[,12:ncol(df_heatmap)], na.rm = TRUE, probs = c(0.01, 0.99))
   col_fun = colorRamp2(c(hm_q[1], 0, hm_q[2]), c(loss, neutral, gain))
   

   
   if (arrangehm == "pearsonR"){
      hm_df <- as.matrix(df_heatmap[,12:ncol(df_heatmap)])
      rownames(hm_df) <- as.factor(df_heatmap$pearsonR)
      arr <- order((rownames(hm_df)))
      split <- c(rep(1, nrow(hm_df)/2), rep(2, nrow(hm_df)/2))
      row_gap <- 5
      filename <- "_pearsonR_"
      hm_df <- hm_df[,2:ncol(hm_df)]
   } else {
      hm_df <- as.matrix(df_heatmap[,13:ncol(df_heatmap)])
      rownames(hm_df) <- as.factor(df_heatmap$pearsonR)
      arr <- NULL
      split <- df_heatmap$PatientID
      row_gap <- 0.4
      filename <- "_bytumor_"
   }
   ht <- Heatmap(hm_df, 
                 name = "log2ratio", column_split = colnames_hm, row_split = split,
                 col =   col_fun,
                 row_title = FALSE,
                 row_gap = unit(row_gap, "mm"),
                 cluster_columns = FALSE, 
                 cluster_rows = FALSE,
                 show_column_names = FALSE,
                 show_row_names = TRUE, 
                 row_labels = df_heatmap$PatientID, 
                 row_order = arr,
                 right_annotation = ha,
                 column_title_gp = gpar(fontsize = 10),
                 column_gap = unit(1, "mm"))
   png(paste0(plotfolder, "heatmap", filename, sample_select[1], ".png"), width = width_px, height = height_px, pointsize = 14 )
   map <- draw(ht, heatmap_legend_side = "bottom")
   dev.off()
   
}
library(data.table)

# to add middle 10
#pearson_vect <- c(sample_annotation_long %>% arrange(desc(pearsonR)) %>% head(n = 20) %>% pull(PatientID), setorder(data.table(sample_annotation_long), pearsonR)[(.N/2 - 20/2):(.N/2 + 20/2 - 1), ] %>% pull(PatientID), sample_annotation_long %>% arrange(desc(pearsonR)) %>% filter(!is.na(pearsonR)) %>% tail(n = 20) %>% pull(PatientID))

pearson_vect <- c(sample_annotation_long %>% filter(PatientID != "patient_101") %>% arrange(desc(pearsonR)) %>% head(n = 30) %>% pull(PatientID), sample_annotation_long %>% filter(PatientID != "patient_101") %>% arrange(desc(pearsonR)) %>% filter(!is.na(pearsonR)) %>% tail(n = 30) %>% pull(PatientID))

makeHeatmap(df_heatmap_init = df_heatmap_init, pearson_vect, width_px = 1200, height_px = 1400, arrangehm = "pearsonR")
## quartz_off_screen 
##                 2

11.1 Adrenal tumors

## quartz_off_screen 
##                 2
heatmap neuroblastoma and ganglioneuroblastoma

heatmap neuroblastoma and ganglioneuroblastoma

11.2 Sarcomas

## quartz_off_screen 
##                 2
heatmap rhabdomyosarcoma, Ewing sarcoma and rhabdomyosarcoma

heatmap rhabdomyosarcoma, Ewing sarcoma and rhabdomyosarcoma

12 Hetereogeneity plots

example heterogeneity plot before pictures of resection are added

example heterogeneity plot before pictures of resection are added

14 Result section in RMarkdown

The results section was written in Rmarkdown, the numbers were pulled immediately from the dataframes in this RMarkdown file. For the code, see the .Rmd file (as opposed to the .html file).

Sample collection. We retrospectively included 285 unique samples (n = 139 plasma, n = 4 CSF, n = 142 tumor tissue) of 140 unique pediatric cancer cases. Patients were recruited at Ghent University Hospital (n = 113), Princess Máxima Center (n = 7), Institut Curie (n = 5) and University Hospital Motol (n = 15). In total, the cohort comprised Ewing sarcoma (n = 9), osteosarcoma (n = 10), rhabdomyosarcoma (n = 11), nephroblastoma (n = 22), neuroblastoma (n = 70) and brain tumor samples (n = 12). More detailed sample information is summarized in supplementary table X. From these 140 patients, copy number aberrations (CNAs) were measured in plasma with shallow whole genome sequencing (sWGS) in all samples, while on tissue this was done either with sWGS (n = 70), WES (n = 5) or array CGH (n = 67). In case of sWGS, 18M [13520196.5-22303950] reads were generated for cfDNA and 39.79M [17697566.5-99577819] for tissue DNA, with 11.38% [8.4250943-15.26553] and 10.51% duplicate reads [6.5794449-17.9417297], respectively.

Copy number abnormality is higher in tumor tissue than in plasma. For every sample, the modified copy number profile abnormality (CPAm) score was calculated (see Methods for details, see figure ##2A and ##2B for an illustration of the relationship between the genome-wide copy number profile and the CPAm score). The median CPAm across all tumor types was found to be 0.796 [0.286075-1.771125] in cfDNA and 2.17315 [0.972925-4.033475] in tissue DNA (figure ###4B illustrates the CPAm score per tumor type). Based on manual inspection (tissue DNA) or the previously established 1% FDR threshold for CPAm (cfDNA, see Methods), we found that 60 (41.0958904%) cfDNA samples and 11 (7.5342466%) tumor samples were labeled as “flat”, i.e., copy number neutral.

cfDNA sample quality and disease extent determines concordance between cfDNA and tissue DNA. Previous studies have pointed at a substantial influence of cfDNA sample quality on the detection of tumor-derived DNA in cfDNA (ADD REFS). We assessed the cfDNA quality by determining the ratio of cfDNA (< 700 bp) vs. high molecular weight (> 700 bp) for 126 samples (3.3507869 [0.521626-15.075385], figure ##1 and supplemental figures #XX). For every cfDNA-tissue pair, the Pearson R and the CPAm score (see Methods) was calculated and associated with the cfDNA/HMW ratio (figure XX, supplemental figures XX). In Figure XX, we observed an apparent influence of cfDNA/HMW ratio and the tissue assay (i.e. Illumina BeadChip, sWGS, WES) on the copy number load in cfDNA. Subsequently, we more deeply investigated the effect of these parameters on the agreement between the tissue CNAs and cfDNA CNAs. Using a generalized additive model (GAM), we found that a higher cfDNA/HMW ratio (after log10 transformation) was associated with a better agreement between tissue CNA and cfDNA CNAs (p < 0.001), after adjusting for tumor type, disease extent and the platform on which the tissue copy number was determined (e.g. sWGS or Illumina BeadChip, full model in supplemental data X). Based on previously-defined thresholds (ref epigenetics), we found that of on a total of 126 samples, the 43 samples with a cfDNA/HMW ratio lower than 1 (low quality) contained 26 (60.4651163%) copy number neutral samples in cfDNA while of these 26 cfDNA neutral samples, there were 38 samples with CNAs in the tumor. Of 31 samples with a ratio between 1 and 5 (intermediate quality) 20 (64.516129%) were copy number neutral (all corresponding tumor samples contained CNAs). Finally, of 52 cfDNA samples with a ratio more than 5 (high quality), 3 (5.7692308%) were copy number neutral. Upon closer inspection of these three cases, the tumor was also copy number neutral in one (patient 008) and contained segmental aberrations in the other two cases (patient 044, patient 206). Overall, disagreement (i.e. tissue DNA containing CNAs while the plasma does not or vice versa) was seen in 1 samples and 50 samples, respectively. The cfDNA/HMW ratio in these 51 discordant samples is 1.11 [0.2558536-2.7754349], while the ratio in the concordant samples is 10.11 [0.9472801-21.7385013]. Furthermore, based on the GAM, patients with metastatic disease had a higher agreements between the log2(ratio) in cfDNA and log2(ratio) in tissue DNA.

Spatial heterogeneity in tumor samples. For two nephroblastoma cases, cfDNA was available at diagnosis and tumor tissue after treatment (patient XX and patient XX). Patient 56 and 57 were treated according to the SIOP Wilms tumor protocol for nephroblastoma (ADDS REFS). Plasma from these two patients was obtained before initiation of chemotherapy and tissue samples were obtained after 4 weeks of neoadjuvant chemotherapy. After resection, the copy number profile was determined in three different locations in the resected kidney and compared to the pre-treatment plasma sample (figure XXX2C), which revealed substantial intra-tumor difference and discordance with cfDNA (e.g. patient 56, gain on chr12, patient 57 both present in cfDNA but not in all tumor sections, figure 2C). For patient 56, histologic evaluation for locations 1 and 2 was determined to be triphasic nephroblastoma with necrosis and location 3 was kidney with blastema. For patient 57, locations 1 and 3 were determined to be triphasic nephroblastoma with rhabdomyoblastic differentiation and location 2 was necrotic tissue. Importantly, gain of 1q, a prognostic biomarker in Wilms tumor (https://pubmed.ncbi.nlm.nih.gov/27432915/), was only observed in location 1 of patient 56 and location 2 and 3 of patient 57, while not in cfDNA at diagnosis.

CNAs can be unique for cfDNA or for tissue DNA. Several samples, of moderate to high quality (cfDNA/HMW ratio above 1) and with a high CPAm (more than 3 times the CPAm at the 1% FDR threshold) in cfDNA were observed to have a low Pearson correlation coefficient with the respective tumor CPAm value (e.g. patient 079, patient 212, patient 077, patient 196). Upon closer inspection, several aberrations are discordant between plasma and tissue DNA (patient 077, patient 079, patient 196, figure XXX). Furthermore, other discordant samples were seen upon manual inspection, albeit with smaller and more subtle differences. In three neuroblastoma cases (patient 185, 136, 109) recurrent segmental CNAs (1p deletion, 2p gain, 11q deletion and 17q gain) were more clearly present in the cfDNA than in the tissue DNA. In one case (patient 212), only the amplification of MYCN on 2p24.3 could be detected in the tissue DNA while analysis of the cfDNA samples showed that many more CNAs were present (figure XXX). For several nephroblastoma cases (e.g. patient 035 and 056), chromosomal aberrations were identified in the cfDNA and not in the tissue DNA.

cfDNA is complementary to tissue DNA in the risk stratification of neuroblastoma and nephroblastoma. As MYCN amplification is an important prognostic biomarker in neuroblastoma, we investigated agreement between MYCN gain/amplification between cfDNA and tissue DNA. On all samples (irrespective of the sample quality) (n = 70), MYCN calls were similar in cfDNA and tissue DNA without any discrepancies. In nephroblastoma, relying on cfDNA for determining the presence of 1q gain, a prognostic marker (ADD REF), 5 samples (n = 24) (or 4/18 when only including the intermediate to high quality samples with a cfDNA/HMW ratio above 1) with 1q gain would have been missed, while only relying on tissue DNA 1q gain would have been missed in 2 cases.

Cerebrospinal fluid is preferable to plasma for medulloblastoma For brain tumors, it is expected that higher tissue DNA fractions will be found in cerebrospinal fluid (CSF) when compared to plasma. We analyzed 3 CSF samples of brain tumor patients. All showed clear CNAs in the CSF (almost) fully concordant to the matching tissue DNA profile (HEATMAP FIGURE). For patient XXX with a medulloblastoma, we had a matching plasma sample available, with a cfDNA/HMW ratio of 1.94, , with a cfDNA/HMW ratio of 1.9498525 that presented a copy number neutral profile, while CSF depicted a chromosome 6 loss (supplemental figure XX).

LS0tCnRpdGxlOiAiVGhlIGZlYXNpYmlsaXR5IG9mIHVzaW5nIGxpcXVpZCBiaW9wc2llcyBhcyBhIGNvbXBsZW1lbnRhcnkgYXNzYXkgZm9yIGNvcHkgbnVtYmVyIGFiZXJyYXRpb24gcHJvZmlsaW5nIGluIHJvdXRpbmVseSBjb2xsZWN0ZWQgcGVkaWF0cmljIGNhbmNlciBwYXRpZW50IHNhbXBsZXMgIgpzdWJ0aXRsZTogIkRhdGEgYW5hbHlzaXMiCmF1dGhvcjogIlJ1YmVuIFZhbiBQYWVtZWwiCmRhdGU6ICJgciBmb3JtYXQoU3lzLnRpbWUoKSwgJyVkICVCLCAlWSwgJUg6JU06JVMnKWAiCm91dHB1dDoKICAgaHRtbF9kb2N1bWVudDoKICAgICAgY29kZV9kb3dubG9hZDogeWVzCiAgICAgIGNvZGVfZm9sZGluZzogaGlkZQogICAgICBkZl9wcmludDogcGFnZWQKICAgICAgZmlnX2NhcHRpb246IHllcwogICAgICBoaWdobGlnaHQ6IGthdGUKICAgICAgbnVtYmVyX3NlY3Rpb25zOiB5ZXMKICAgICAgdGhlbWU6IGNvc21vCiAgICAgIHRvYzogeWVzCiAgICAgIHRvY19mbG9hdDogeWVzCi0tLQoKPHN0eWxlPgpib2R5IHsKdGV4dC1hbGlnbjoganVzdGlmeX0KPC9zdHlsZT4KCgojIEludHJvZHVjdGlvbgpJbiBvdXIgZGF0YXNldCwgd2UgaGF2ZSBkaWZmZXJlbnQgZGF0YXR5cGVzOgotIFdob2xlIGdlbm9tZSBzZXF1ZW5jaW5nIGF0IHNoYWxsb3cgZGVwdGggKHNXR1MpCi0gQWdpbGVudCAxODBLIGFycmF5cwotIElsbHVtaW5hIEh1bWFuQ3l0b1NOUCBkYXRhCgpUaGVzZSBuZWVkcyB0byBiZSBoYXJtb25pc2VkIGZpcnN0IHNvIHRoYXQgdGhleSBjYW4gYmUgcmVhZCBpbnRvIFIuCgojIyBzV0dTClRoZSBmYXN0cSBmaWxlcyB3ZXJlIHByZXByb2Nlc3NlZCB3aXRoIGAuL2NvZGUvcHJlcHJvY2Vzc2luZy9zV0dTX3BpcGVsaW5lX1NFLnNuYWtlZmlsZWAsIHdoaWNoIHJ1bnMgYndhLW1lbSwgcGljYXJkIG1hcmtkdXBsaWNhdGVzIGFuZCBXaXNlY29uZG9yWC9pY2hvckNOQS4gVGhlIG91dHB1dCAoYGJpbnMuYmVkYCwgYHNlZ21lbnRzLmJlZGApIGZyb20gV2lzZWNvbmRvclggd2VyZSBmdXJ0aGVyIHVzZWQgaW4gdGhlIGRvd25zdHJlYW0gcHJvY2Vzc2luZy4gVGhlIHJlZmVyZW5jZSBmb3IgV2lzZWNvbmRvclggd2FzIGdlbmVyYXRlZCBmcm9tIGFuIGluLWhvdXNlIGRhdGFzZXQgb2YgaGVhbHRoeSB2b2x1bnRlZXJzLiBNb3JlIGluZm9ybWF0aW9uIG9uIGhvdyB0byBvYnRhaW4gYSByZWZlcmVuY2UgZGF0YXNldCBmb3IgV2lzZWNvbmRvclggaXMgYXZhaWxhYmxlIGF0IGh0dHBzOi8vZ2l0aHViLmNvbS9DZW50ZXJGb3JNZWRpY2FsR2VuZXRpY3NHaGVudC9XaXNlY29uZG9yWC4gVGhlIFBvTiBhbmQgc3VwcG9ydGluZyBmaWxlcyBmb3IgaWNob3JDTkEgd2VyZSBvYnRhaW5lZCBmcm9tIHRoZSBpY2hvckNOQSByZXBvc2l0b3J5IChodHRwczovL2dpdGh1Yi5jb20vYnJvYWRpbnN0aXR1dGUvaWNob3JDTkEpLgoKIyMgV0VTClRoZSBmYXN0cSBmaWxlcyB3ZXJlIHByZXByb2Nlc3NlZCB3aXRoIGAuL2NvZGUvcHJlcHJvY2Vzc2luZy9zV0dTX3BpcGVsaW5lX1BFLnNuYWtlZmlsZWAsIHdoaWNoIHJ1bnMgYndhLW1lbSwgcGljYXJkIG1hcmtkdXBsaWNhdGVzIGFuZCBXaXNlY29uZG9yWC9pY2hvckNOQS4gCgpDTlZraXQgd2FzIHJ1biB3aXRoIHRoZSBwYXJhbWV0ZXJzIGRlc2NyaWJlZCBpbiBgY252a2l0LnNoYCBvbiB0aGUgZGVkdXBsaWNhdGVkIGJhbSBmaWxlcyB3aXRoIHRoZSBwYWlyZWQgZ2VybWxpbmUgc2FtcGxlLiBUYXJnZXQgcmVnaW9uIGJlZCBmaWxlcyAoZS5nLiBTdXJlU2VsZWN0KSB3YXMgZG93bmxvYWRlZCBmcm9tIHRoZSBBZ2lsZW50IHdlYnNpdGUuIFRoZSBsaW5rIGJldHdlZW4gdGhlIElEIGZyb20gZ2VybWxpbmUgV0VTIGFuZCBJRCBmcm9tIHR1bW9yIFdFUyBpcyBhbHNvIGluIHRoZSBgY252a2l0LnNoYCBmaWxlLiAKCiMjIElsbHVtaW5hIEh1bWFuQ3l0b1NOUApJbGx1bWluYSBHZW5vbWVzdHVkaW8gMi4wIChodHRwczovL3d3dy5pbGx1bWluYS5jb20vdGVjaG5pcXVlcy9taWNyb2FycmF5cy9hcnJheS1kYXRhLWFuYWx5c2lzLWV4cGVyaW1lbnRhbC1kZXNpZ24vZ2Vub21lc3R1ZGlvLmh0bWwpIHdhcyB1c2VkIHRvIG9idGFpbiB0aGUgbG9nMnJhdGlvIChSb2JzL1JleHApIHBlciBiaW4gZnJvbSB0aGUgSURBVCBmaWxlcy4gVGhlIFNhbXBsZVNoZWV0cyBhcmUgYXZhaWxhYmxlIGluIGAuL3Jlc291cmNlcy9gLiBUaGUgb3RoZXIgZmlsZXMgKGAuZWd0YCBhbmQgYC5icG1gIGFyZSB0b28gbGFyZ2UgdG8gaG9zdCBoZXJlIGFuZCBhcmUgYXZhaWxhYmxlIG9uIHRoZSBJbGx1bWluYSB3ZWJzaXRlIChlLmcuIGh0dHBzOi8vZW1lYS5zdXBwb3J0LmlsbHVtaW5hLmNvbS9kb3dubG9hZHMvaHVtYW5jeXRvc25wLTEydjItMV9wcm9kdWN0X2ZpbGVzLW5zLmh0bWwpCgojIyBBZ2lsZW50IDE4MEsgYXJyYXkKUmF3IGRhdGEgZm9yIHRoZSBBZ2lsZW50IDE4MEsgYXJyYXlzIHdhcyBub3QgYXZhaWxhYmxlLiBUaGUgcHJvY2Vzc2VkIGRhdGEgKGBzYW1wbGVfcmF3LmNzdmApIHdhcyB1c2VkIGZvciBkb3duc3RyZWFtIHByb2Nlc3NpbmcuIFRoZSBkYXRhIHdhcyBwcm9jZXNzZWQgYWNjb3JkaW5nIHRvIHRoZSBtZXRob2RzIGluIGh0dHBzOi8vcHVibWVkLm5jYmkubmxtLm5paC5nb3YvMjMzMDgxMDgvLiAKCiMjIEludGVncmF0aW5nIHRoZSBkaWZmZXJlbnQgcGxhdGZvcm1zCmAuL2NvZGUvY29udmVydFJhdy5zbmFrZWZpbGVgOiBjb252ZXJ0cyBkYXRhIGZyb20gb2J0YWluZWQgZnJvbSBXRVMsIHNXR1MsIElsbHVtaW5hIEh1bWFuQ3l0b1NOUC0xMiBvciAxODBLIGFycmF5IChBZ2lsZW50KSBpbnRvIGEgc3RydWN0dXJlIHRoYXQgYWxsb3dzIHRoZSBjb21wYXJpc29uIG9mIHRoZXNlIGRpZmZlcmVudCBkYXRhLXR5cGVzLCBhbmQgaGFybW9uaXNlcyB0aGUgYmluIHNpemUgYmV0d2VlbiBhbGwgZGF0YSB0eXBlcy4gQWxzbyB1c2VzIEROQWNvcHkgdG8gb2J0YWluIHNlZ21lbnRhdGlvbnMuIElmIG5lY2Vzc2FyeSAoaS5lLiBhcnJheSBkYXRhKSwgdGhlIGZpbGVzIGFyZSBsaWZ0b3ZlciB0byBHUkNoMzguCgpFeGFtcGxlIGlucHV0IGZpbGVzIGFyZSBwcmVzZW50IGluIHRoZSBgLi9leGFtcGxlcy9gIGZvbGRlci4gCgojIyBPdGhlciBzY3JpcHRzCmAuL2NvZGUvbWFrZUJpbnMuc2hgIG9idGFpbiBiaW5zIG9mIGNob2ljZSBzdGFydGluZyBmcm9tIGAuZmEuZmFpYCBmaWxlLCBpcyBhIGRlcGVuZGVuY3kgb2YgYC4vY29kZS9jb252ZXJ0UmF3LnNuYWtlZmlsZWAKCmAuL2NvZGUvRE5BY29weV9zZWdtZW50LlJgOiBydW5zIEROQWNvcHksIGlzIGEgZGVwZW5kZW5jeSBvZiBgLi9jb2RlL2NvbnZlcnRSYXcuc25ha2VmaWxlYAoKIyMgTG9hZCBkZXBlbmRlbmNpZXMgYW5kIHBhY2thZ2VzCmBgYHtyLCB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFfQprbml0cjo6b3B0c19jaHVuayRzZXQod2FybmluZz1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgY2FjaGUgPSBUUlVFKQpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeSh3ZXNhbmRlcnNvbikKbGlicmFyeShnZ3B1YnIpCmxpYnJhcnkoem9vKQpsaWJyYXJ5KHJlYWR4bCkKbGlicmFyeShyZXNoYXBlMikKbGlicmFyeShDb21wbGV4SGVhdG1hcCkKbGlicmFyeShxdWVlbnNnYW1iaXQpICNodHRwczovL2dpdGh1Yi5jb20vcm12cGFlbWUvcXVlZW5zZ2FtYml0CmxpYnJhcnkoY2lyY2xpemUpCmxpYnJhcnkoUkNvbG9yQnJld2VyKQpsaWJyYXJ5KGdnYmVlc3dhcm0pCmxpYnJhcnkoZ2dyaWRnZXMpCmxpYnJhcnkoY29uZmxpY3RlZCkKbGlicmFyeShzalBsb3QpCmxpYnJhcnkoZ2dyZXBlbCkKbGlicmFyeShEVCkKY29uZmxpY3RfcHJlZmVyKCJmaWx0ZXIiLCAiZHBseXIiKQoKb3B0aW9ucyhzY2lwZW49OTk5KQpjb2xvcnRoZW1lIDwtIGMod2VzX3BhbGV0dGUoIkNhdmFsY2FudGkxIilbMV0sIHdlc19wYWxldHRlKCJDYXZhbGNhbnRpMSIpWzRdKQoKY2hyX29yZGVyIDwtIGMoIjEiLCAiMiIsICIzIiwgIjQiLCAiNSIsICI2IiwgIjciLCAiOCIsCiAgICAgICAgICAgICAgICI5IiwgIjEwIiwgIjExIiwgIjEyIiwgIjEzIiwgIjE0IiwgIjE1IiwKICAgICAgICAgICAgICAgIjE2IiwgIjE3IiwgIjE4IiwgIjE5IiwgIjIwIiwgIjIxIiwgIjIyIiwgIlgiLCAiWSIpCgpkYXRhZGlyX3NXR1NfY2ZETkEgPC0gIi4vZGF0YS9zV0dTX2NmRE5BLyIKZGF0YWRpcl9zV0dTX3Rpc3N1ZSA8LSAiLi9kYXRhL3NXR1NfdGlzc3VlLyIKZGF0YWRpcl9hcnJheUJFIDwtICIuL2RhdGEvYXJyYXkvIgpkYXRhZGlyX2FycmF5Q1ogPC0gIi4vZGF0YS9TTlBhcnJheS8iCmRhdGFkaXJfV0VTIDwtICIuL2RhdGEvV0VTX0ZSLyIKZGF0YWRpcl9oZWFsdGh5IDwtICIuL2RhdGEvc1dHU19oZWFsdGh5LyIKcGxvdGZvbGRlciA8LSAiLi9wbG90cy8iCmBgYAoKYGBge3J9CiMgdGhlIG9yaWdpbmFsIENQQSBmcm9tIFJhbWFuIGV0IGFsLgpnZXQuY3BhIDwtIGZ1bmN0aW9uKHNlZyl7CiAgIGNwYSA8LSBzdW0oYWJzKHNlZyR6c2NvcmUpICogKHNlZyRlbmQgLSBzZWckc3RhcnQgICsgMSkpIC8gbnJvdyhzZWcpICogMWUtOCAjIHBlciAxMDAgTWIKICAgcmV0dXJuKGNwYSkKfQoKIyBUaGUgbW9kaWZpZWQgQ1BBIHNjb3JlIChDUEFtKQpnZXQuY3BhLm1vZGlmaWVkMiA8LSBmdW5jdGlvbihzZWcpewogICBjcGEgPC0gc3VtKGFicyhzZWckcmF0aW8pICogKHNlZyRlbmQgLSBzZWckc3RhcnQgKyAxKSkgLyAxZTgKICAgcmV0dXJuKGNwYSkKfQoKbWFrZUNOVmNvbXBhcmlzb24gPC0gZnVuY3Rpb24oZGF0YWRpcjEsIGRhdGFkaXIyLCBzYW1wbGUxLCBzYW1wbGUyLCBwYXRpZW50SUQsIHVuaXF1ZUlELCBiaW5zaXplLCB0dW1vcl9pbnB1dCwgdHVtb3J0eXBlLCB0aXNzdWVwbGF0Zm9ybSl7CiAgIAogICBwcmludChwYXN0ZTAoImNmRE5BIHNhbXBsZTogIiwgc2FtcGxlMSkpCiAgIHByaW50KHBhc3RlMCgidHVtb3JETkEgc2FtcGxlOiAiLCBzYW1wbGUyKSkKICAgcHJpbnQocGFzdGUwKCJiaW5zaXplOiAiLCBiaW5zaXplKSkKICAgCiAgIAogICBiaW5zX3RvcCA8LSByZWFkX3RzdihwYXN0ZTAoZGF0YWRpcjEsIHN0cl9zdWJzZXQoZGlyKGRhdGFkaXIxLCBwYXR0ZXJuID0gc2FtcGxlMSksICJiaW5zX21hc2siKSksIGNvbF90eXBlcyA9IGMoImZkZD9kIiksCiAgICAgICAgICAgICAgICAgICAgICAgIGNvbF9uYW1lcyA9IGMoImNociIsICJzdGFydCIsICJlbmQiLCAiaWQiLCAicmF0aW8iKSwgc2tpcCA9IDEpCiAgIGJpbnNfdG9wIDwtIGJpbnNfdG9wICU+JSBmaWx0ZXIoIWNociAlaW4lIGMoIlgiLCAiWSIsICIyMyIsICIyNCIpKQogICAKICAgc2Vnc190b3AgPC0gcmVhZF90c3YocGFzdGUwKGRhdGFkaXIxLCBzdHJfc3Vic2V0KGRpcihkYXRhZGlyMSwgcGF0dGVybiA9IHNhbXBsZTEpLCAic2VnbWVudHNfbWFzay5iZWQiKSksIGNvbF90eXBlcyA9IGMoImZkZGRkIiksCiAgICAgICAgICAgICAgICAgICAgICAgIGNvbF9uYW1lcyA9IGMoImNociIsICJzdGFydCIsICJlbmQiLCAicmF0aW8iLCAienNjb3JlIikpCiAgIHNlZ3NfdG9wIDwtIHNlZ3NfdG9wICU+JSBmaWx0ZXIoIWNociAlaW4lIGMoIlgiLCAiWSIsICIyMyIsICIyNCIpKSAlPiUgbXV0YXRlKFNhbXBsZSA9IHNhbXBsZTEpCiAgIAogICBpZiAodHVtb3JfaW5wdXQgPT0gImFycmF5X0JFIiB8IHR1bW9yX2lucHV0ID09ICJhcnJheV9DWiIgfCB0dW1vcl9pbnB1dCA9PSAiV0VTX0ZSIiApewogICAgICBiaW5zX2JvdHRvbSA8LSAgcmVhZF90c3YocGFzdGUwKGRhdGFkaXIyLCIvIixzYW1wbGUyLCJfIiwgYmluc2l6ZSwgIi50c3YiKSwgY29sX3R5cGVzID0gYygiZmRkZCIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sX25hbWVzID0gYygiY2hyIiwgInN0YXJ0IiwgImVuZCIsICJyYXRpbyIpKQogICAgICBiaW5zX2JvdHRvbSA8LSBiaW5zX2JvdHRvbSAlPiUgZmlsdGVyKCFjaHIgJWluJSBjKCJYIiwgIlkiLCAiMjMiLCAiMjQiKSkKICAgICAgYmluc19ib3R0b20kY2hyIDwtIGZhY3RvcihiaW5zX2JvdHRvbSRjaHIsIGxldmVscyA9IGNocl9vcmRlcikKICAgICAgCiAgICAgIHNlZ3NfYm90dG9tIDwtIHJlYWRfdHN2KHBhc3RlMChkYXRhZGlyMiwiLyIsc2FtcGxlMiwiXyIsIGJpbnNpemUsICJfc2VnbWVudHMudHN2IiksIGNvbF90eXBlcyA9IGMoImZkZGQiKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sX25hbWVzID0gYygiY2hyIiwgInN0YXJ0IiwgImVuZCIsICJyYXRpbyIpLCBza2lwID0gMSkKICAgICAgCiAgICAgIHNlZ3NfYm90dG9tIDwtIHNlZ3NfYm90dG9tICU+JSBmaWx0ZXIoIWNociAlaW4lIGMoIlgiLCAiWSIsICIyMyIsICIyNCIpKSAlPiUgbXV0YXRlKFNhbXBsZSA9IHNhbXBsZTIpCiAgICAgIHNlZ3NfYm90dG9tJGNociA8LSBmYWN0b3Ioc2Vnc19ib3R0b20kY2hyLCBsZXZlbHMgPSBjaHJfb3JkZXIpCiAgIH0gZWxzZSBpZiAodHVtb3JfaW5wdXQgPT0gInNXR1MiKXsKICAgICAgYmluc19ib3R0b20gPC0gIHJlYWRfdHN2KHBhc3RlMChkYXRhZGlyMiwgc3RyX3N1YnNldChkaXIoZGF0YWRpcjIsIHBhdHRlcm4gPSBzYW1wbGUyKSwgImJpbnNfbWFzayIpKSwgY29sX3R5cGVzID0gYygiZmRkP2QiKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbF9uYW1lcyA9IGMoImNociIsICJzdGFydCIsICJlbmQiLCAiaWQiLCAicmF0aW8iKSkKICAgICAgYmluc19ib3R0b20gPC0gYmluc19ib3R0b20gJT4lIGZpbHRlcighY2hyICVpbiUgYygiWCIsICJZIiwgIjIzIiwgIjI0IikpCiAgICAgIGJpbnNfYm90dG9tJGNociA8LSBmYWN0b3IoYmluc19ib3R0b20kY2hyLCBsZXZlbHMgPSBjaHJfb3JkZXIpCiAgICAgIAogICAgICBzZWdzX2JvdHRvbSA8LSByZWFkX3RzdihwYXN0ZTAoZGF0YWRpcjIsIHN0cl9zdWJzZXQoZGlyKGRhdGFkaXIyLCBwYXR0ZXJuID0gc2FtcGxlMiksICJzZWdtZW50c19tYXNrLmJlZCIpKSwgY29sX3R5cGVzID0gYygiZmRkZGQiKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sX25hbWVzID0gYygiY2hyIiwgInN0YXJ0IiwgImVuZCIsICJyYXRpbyIsICJ6c2NvcmUiKSkKICAgICAgc2Vnc19ib3R0b20gPC0gc2Vnc19ib3R0b20gJT4lIGZpbHRlcighY2hyICVpbiUgYygiWCIsICJZIiwgIjIzIiwgIjI0IikpICU+JSBtdXRhdGUoU2FtcGxlID0gc2FtcGxlMikKICAgICAgc2Vnc19ib3R0b20kY2hyIDwtIGZhY3RvcihzZWdzX2JvdHRvbSRjaHIsIGxldmVscyA9IGNocl9vcmRlcikKICAgfQogICAKICAgY29sb3JfdG9wIDwtIHdlc19wYWxldHRlKCJDYXZhbGNhbnRpMSIpWzFdCiAgIGNvbG9yX2JvdHRvbSA8LSB3ZXNfcGFsZXR0ZSgiQ2F2YWxjYW50aTEiKVs0XQogICBjb2xvcl9hYmJlcmF0aW9ucyA8LSB3ZXNfcGFsZXR0ZSgiQ2F2YWxjYW50aTEiKVs1XQogICAKICAgbWF4LnJhdGlvX2JpbnMgPC0gbWF4KGMoYmluc190b3AkcmF0aW8sIGJpbnNfYm90dG9tJHJhdGlvKSwgbmEucm0gPSBUUlVFKQogICBtaW4ucmF0aW9fYmlucyA8LSBtaW4oYyhiaW5zX3RvcCRyYXRpbywgYmluc19ib3R0b20kcmF0aW8pLCBuYS5ybSA9IFRSVUUpCiAgIAogICBtYXgucmF0aW9fYmlucy50b3AgPC0gbWF4KGMoYmluc190b3AkcmF0aW8pLCBuYS5ybSA9IFRSVUUpCiAgIG1pbi5yYXRpb19iaW5zLnRvcCA8LSBtaW4oYyhiaW5zX3RvcCRyYXRpbyksIG5hLnJtID0gVFJVRSkKICAgCiAgIG1heC5yYXRpb19iaW5zLmJvdHRvbSA8LSBtYXgoYyhiaW5zX2JvdHRvbSRyYXRpbyksIG5hLnJtID0gVFJVRSkKICAgbWluLnJhdGlvX2JpbnMuYm90dG9tIDwtIG1pbihjKGJpbnNfYm90dG9tJHJhdGlvKSwgbmEucm0gPSBUUlVFKQogICAKICAgCiAgIGlmICh0dW1vcl9pbnB1dCA9PSAic1dHUyIpewogICAgICBjcGFfdG9wIDwtIHJvdW5kKGdldC5jcGEoc2Vnc190b3ApLDQpCiAgICAgIGNwYV9ib3R0b20gPC0gcm91bmQoZ2V0LmNwYShzZWdzX2JvdHRvbSksNCkKICAgICAgY3BhX3RvcCA8LSByb3VuZChnZXQuY3BhLm1vZGlmaWVkMihzZWdzX3RvcCksNCkKICAgICAgY3BhX2JvdHRvbSA8LSByb3VuZChnZXQuY3BhLm1vZGlmaWVkMihzZWdzX2JvdHRvbSksNCkKICAgICAgY3BhLmNhbGMgPC0gIkNQQW0iCiAgIH0gZWxzZXsKICAgICAgY3BhX3RvcCA8LSByb3VuZChnZXQuY3BhLm1vZGlmaWVkMihzZWdzX3RvcCksNCkKICAgICAgY3BhX2JvdHRvbSA8LSByb3VuZChnZXQuY3BhLm1vZGlmaWVkMihzZWdzX2JvdHRvbSksNCkKICAgICAgY3BhLmNhbGMgPC0gIkNQQW0iCiAgIH0KICAgCiAgIGlmICh0dW1vcnR5cGUgPT0gIm5ldXJvYmxhc3RvbWEiKXsKICAgICAgIyBhZGQgTVlDTiByZWdpb24KICAgICAgbmJsXzEgPC0gZ2VvbV9zZWdtZW50KGRhdGEgPSBzZWdzX3RvcCAlPiUgZmlsdGVyKGNociA9PSAiMiIpLCBhZXMoeD0xNTk0MDU1MCwgeGVuZD0xNTk0NzAwNCwgeT0tSW5mLCB5ZW5kPUluZiksIGNvbCA9ICJncmV5IiwgYWxwaGEgPSAwLjQpIAogICAgICBuYmxfMiA8LSBnZW9tX3RleHQoZGF0YSA9IHNlZ3NfdG9wICU+JSBmaWx0ZXIoY2hyID09ICIyIiksIGxhYmVsID0gIk1ZQ04iLCB4PTY1OTQ3MDA0LCB5PW1heC5yYXRpb19iaW5zKjAuOSwgYW5nbGUgPSA5MCwgYWxwaGEgPSAwLjQsIHNpemUgPSAzLCBjb2xvciA9ICJncmV5IikKICAgfSBlbHNlIHsKICAgICAgbmJsXzEgPC0gTlVMTAogICAgICBuYmxfMiA8LSBOVUxMCiAgIH0KICAgCiAgIHB0b3AgPC0gZ2dwbG90KGJpbnNfdG9wLCBhZXMoeCA9IHN0YXJ0LCB5ID0gcmF0aW8pKSArIAogICAgICB0aGVtZV9idygpICsgCiAgICAgIGxhYnModGl0bGUgPSBwYXN0ZTAocGF0aWVudElELCAiIC0gc1dHUyBjZkROQSAtICIsIHNhbXBsZTEsICIgLSAiLCBjcGEuY2FsYywiOiAiLCBjcGFfdG9wLCAiIC0gIiwgdHVtb3J0eXBlKSwgeSA9ICJsb2cyKHJhdGlvKSIpICsgCiAgICAgIGdlb21fcG9pbnQoc2l6ZSA9IDAuMywgY29sID0gY29sb3JfdG9wLCBhbHBoYSA9IDAuNykgKwogICAgICBsaW1zKHkgPSBjKG1pbi5yYXRpb19iaW5zLG1heC5yYXRpb19iaW5zKSkrCiAgICAgIHRoZW1lKHBhbmVsLnNwYWNpbmcueCA9IHVuaXQoMCwgImxpbmVzIiksCiAgICAgICAgICAgIHBhbmVsLnNwYWNpbmcueSA9IHVuaXQoMCwgImxpbmVzIiksCiAgICAgICAgICAgIGF4aXMudGl0bGUueCA9ICBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgICAgIGF4aXMudGV4dC54ID0gIGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgICAgYXhpcy50aWNrcy54ID0gIGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgICAgc3RyaXAuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChjb2xvciA9ICJ3aGl0ZSIsIGZpbGwgPSAid2hpdGUiKSwKICAgICAgICAgICAgIyAgIHBhbmVsLmJvcmRlciA9IGVsZW1lbnRfcmVjdChjb2xvciA9ICJncmF5IiwgZmlsbCA9IE5BLCBzaXplID0gMC4zKSwgCiAgICAgICAgICAgIHBhbmVsLmdyaWQubWFqb3IgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgICAgIHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X2JsYW5rKCkpICsgCiAgICAgIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDAsIGxpbmV0eXBlID0gImRhc2hlZCIsIGNvbCA9ICJncmF5IikgKwogICAgICBmYWNldF93cmFwKH5jaHIsIHN0cmlwLnBvc2l0aW9uID0gImJvdHRvbSIsIHNjYWxlcyA9ImZyZWVfeCIsIG5yb3cgPSAxKSArIAogICAgICBnZW9tX3NlZ21lbnQoZGF0YSA9IHNlZ3NfdG9wLCBhZXMoeCA9IHN0YXJ0LCB4ZW5kID0gZW5kLCB5ID0gcmF0aW8gLCB5ZW5kID0gcmF0aW8pLCBjb2wgPSBjb2xvcl9hYmJlcmF0aW9ucykgKwogICAgICBnZW9tX3JlY3QoZGF0YSA9IHNlZ3NfdG9wLCBhZXMoeG1pbj1zdGFydCwgeG1heD1lbmQsIHltaW49MCwgeW1heD1yYXRpbyksIGZpbGwgPSBjb2xvcl9hYmJlcmF0aW9ucywgYWxwaGEgPSAwLjQpICsgbmJsXzEgKyBuYmxfMgogICAKICAgCiAgIHBib3R0b20gPC0gZ2dwbG90KGJpbnNfYm90dG9tLCBhZXMoeCA9IHN0YXJ0LCB5ID0gcmF0aW8pKSArIAogICAgICB0aGVtZV9idygpICsgCiAgICAgIGxhYnModGl0bGUgPSBwYXN0ZTAocGF0aWVudElELCAiIC0gIiwgdGlzc3VlcGxhdGZvcm0sICIgdGlzc3VlIC0gIiwgc2FtcGxlMiwgIiAtICIsY3BhLmNhbGMsICI6ICIsIGNwYV9ib3R0b20sICIgLSAiLCB0dW1vcnR5cGUpLCB5ID0gImxvZzIocmF0aW8pIikgKyAgCiAgICAgIGdlb21fcG9pbnQoc2l6ZSA9IDAuMywgY29sID0gY29sb3JfYm90dG9tLCBhbHBoYSA9IDAuNykgKwogICAgICBsaW1zKHkgPSBjKG1pbi5yYXRpb19iaW5zLG1heC5yYXRpb19iaW5zKSkrCiAgICAgIHRoZW1lKHBhbmVsLnNwYWNpbmcueCA9IHVuaXQoMCwgImxpbmVzIiksCiAgICAgICAgICAgIHBhbmVsLnNwYWNpbmcueSA9IHVuaXQoMCwgImxpbmVzIiksCiAgICAgICAgICAgIGF4aXMudGl0bGUueCA9ICBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgICAgIGF4aXMudGV4dC54ID0gIGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgICAgYXhpcy50aWNrcy54ID0gIGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgICAgc3RyaXAuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChjb2xvciA9ICJ3aGl0ZSIsIGZpbGwgPSAid2hpdGUiKSwKICAgICAgICAgICAgcGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgICAgcGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgICAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSkgKyAKICAgICAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCwgbGluZXR5cGUgPSAiZGFzaGVkIiwgY29sID0gImdyYXkiKSArCiAgICAgIGZhY2V0X3dyYXAofmNociwgc3RyaXAucG9zaXRpb24gPSAiYm90dG9tIiwgc2NhbGVzID0iZnJlZV94IiwgbnJvdyA9IDEpICsKICAgICAgZ2VvbV9zZWdtZW50KGRhdGEgPSBzZWdzX2JvdHRvbSwgYWVzKHggPSBzdGFydCwgeGVuZCA9IGVuZCwgeSA9IHJhdGlvICwgeWVuZCA9IHJhdGlvKSwgY29sID0gY29sb3JfYWJiZXJhdGlvbnMpICsKICAgICAgZ2VvbV9yZWN0KGRhdGEgPSBzZWdzX2JvdHRvbSwgYWVzKHhtaW49c3RhcnQsIHhtYXg9ZW5kLCB5bWluPTAsIHltYXg9cmF0aW8pLCBmaWxsID0gY29sb3JfYWJiZXJhdGlvbnMsIGFscGhhID0gMC40KSArIG5ibF8xICsgbmJsXzIKICAgCiAgIAogICBjb3JwbG90X2RmX2JpbnMgPC0gaW5uZXJfam9pbihiaW5zX3RvcCwgYmluc19ib3R0b20sIGJ5ID0gYygiY2hyIiwgInN0YXJ0IiwgImVuZCIpKQogICAjY29ycGxvdF9kZiA8LSBjb3JwbG90X2RmICU+JSBmaWx0ZXIoIWlzLm5hKHJhdGlvLngpICYgIWlzLm5hKHJhdGlvLnkpKQogICAKICAgY29ycGxvdF9kZl9iaW5zIDwtIGNvcnBsb3RfZGZfYmlucyAlPiUKICAgICAgbXV0YXRlKHJNLnRvcD1yb2xsYXBwbHkocmF0aW8ueCwxMDAsIEZVTj1mdW5jdGlvbih4KSBtZWFuKHgsIG5hLnJtPVRSVUUpLCBmaWxsPU5BLCBhbGlnbj0icmlnaHQiKSkgJT4lCiAgICAgIG11dGF0ZShyTS5ib3R0b209cm9sbGFwcGx5KHJhdGlvLnksMTAwLCBGVU49ZnVuY3Rpb24oeCkgbWVhbih4LCBuYS5ybT1UUlVFKSwgZmlsbD1OQSwgYWxpZ249InJpZ2h0IikpIAogICAKICAgcm9sbG1lYW4gPC0gZ2dwbG90KHRpYmJsZShjb3JwbG90X2RmX2JpbnMpLCBhZXMoeCA9IHN0YXJ0KSkgKyAKICAgICAgdGhlbWVfYncoKSArIAogICAgICBsYWJzKHkgPSAibG9nMihyYXRpbykiLCB4ID0gImNocm9tb3NvbWVzIikgKwogICAgICBnZW9tX2xpbmUoYWVzKHk9ck0uYm90dG9tKSwgY29sID0gY29sb3JfYm90dG9tLCBhbHBoYSA9IDEsIHNpemUgPSAxKSArCiAgICAgIGdlb21fbGluZShhZXMoeT1yTS50b3ApLCBjb2wgPSBjb2xvcl90b3AsIGFscGhhID0gMC43LCBzaXplID0gMSkgKwogICAgICB0aGVtZShwYW5lbC5zcGFjaW5nLnggPSB1bml0KDAsICJsaW5lcyIpLAogICAgICAgICAgICBwYW5lbC5zcGFjaW5nLnkgPSB1bml0KDAsICJsaW5lcyIpLAogICAgICAgICAgICAjICBheGlzLnRpdGxlLnggPSAgZWxlbWVudF9ibGFuaygpLAogICAgICAgICAgICBheGlzLnRleHQueCA9ICBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgICAgIGF4aXMudGlja3MueCA9ICBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgICAgIHN0cmlwLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoY29sb3IgPSAid2hpdGUiLCBmaWxsID0gIndoaXRlIiksCiAgICAgICAgICAgIHBhbmVsLmdyaWQubWFqb3IgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgICAgIHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X2JsYW5rKCkpICsgCiAgICAgIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDAsIGxpbmV0eXBlID0gImRhc2hlZCIsIGNvbCA9ICJncmF5IikgKwogICAgICBmYWNldF93cmFwKH5jaHIsIHN0cmlwLnBvc2l0aW9uID0gImJvdHRvbSIsIHNjYWxlcyA9ImZyZWVfeCIsIG5yb3cgPSAxKSArIGxpbXMoeSA9IGMoLU5BLE5BKSkrIG5ibF8xCiAgIAogICBtYXgucmF0aW8gPC0gbWF4KGMoY29ycGxvdF9kZl9iaW5zJHJhdGlvLngsIGNvcnBsb3RfZGZfYmlucyRyYXRpby55KSwgbmEucm0gPSBUUlVFKQogICBtaW4ucmF0aW8gPC0gbWluKGMoY29ycGxvdF9kZl9iaW5zJHJhdGlvLngsIGNvcnBsb3RfZGZfYmlucyRyYXRpby55KSwgbmEucm0gPSBUUlVFKQogICBjb3JwbG90IDwtIGdncGxvdChjb3JwbG90X2RmX2JpbnMsIGFlcyh4ID0gcmF0aW8ueCwgeSA9IHJhdGlvLnkpKSArIAogICAgICBnZW9tX3BvaW50KHNpemUgPSAwLjMsIGNvbCA9IHdlc19wYWxldHRlKCJSb3lhbDEiKVsxXSkgKyAKICAgICAgdGhlbWVfYncoKSArCiAgICAgIGdlb21fYWJsaW5lKHNsb3BlID0gMSwgaW50ZXJjZXB0ID0gMCkgKwogICAgICBzdGF0X2NvcihtZXRob2QgPSAicGVhcnNvbiIsIGFlcyhsYWJlbCA9IC4uci5sYWJlbC4uKSkgKwogICAgICBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iLCBjb2wgPSBjb2xvcl9hYmJlcmF0aW9ucywgbGluZXR5cGUgPSAiZGFzaGVkIikgKwogICAgICBsaW1zKHggPSBjKG1pbi5yYXRpbyAsIG1heC5yYXRpbyksIHkgPSBjKG1pbi5yYXRpbywgbWF4LnJhdGlvKSkgKyAKICAgICAgbGFicyh4ID0gImxvZzIocmF0aW8pIGNmRE5BIiwgeSA9ICJsb2cyKHJhdGlvKSB0aXNzdWUiKSArCiAgICAgIHRoZW1lKGF4aXMudGl0bGUueCA9IGVsZW1lbnRfdGV4dChjb2xvciA9IGNvbG9yX3RvcCksCiAgICAgICAgICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfdGV4dChjb2xvciA9IGNvbG9yX2JvdHRvbSkpCiAgIAogICBSIDwtIGNvcihjb3JwbG90X2RmX2JpbnMkcmF0aW8ueCwgY29ycGxvdF9kZl9iaW5zJHJhdGlvLnksIHVzZSA9ICJjb21wbGV0ZS5vYnMiLCBtZXRob2QgPSAicGVhcnNvbiIpCiAgIAogICBDTlZwbG90IDwtIGdnYXJyYW5nZShwdG9wLCBwYm90dG9tLCBucm93ID0gMiwgbmNvbCA9IDEsIGFsaWduID0gInYiLCBoZWlnaHRzID0gYygxLCAxKSkKICAgY29tcGFyaXNvbnMgPC0gZ2dhcnJhbmdlKHJvbGxtZWFuLCBjb3JwbG90LCBucm93ID0gMSwgbmNvbCA9IDIsIHdpZHRocyA9IGMoMC43LCAwLjMpKQogICAKICAgYXJyYW5nZXBsb3QgPC0gZ2dhcnJhbmdlKENOVnBsb3QsIGNvbXBhcmlzb25zLCBucm93ID0gMiwgaGVpZ2h0cyA9IGMoMC43NSwgMC4yNSksIHdpZHRocyA9IGMoMSwgMC45MCksIGFsaWduID0gImh2IikKICAgZ2dzYXZlKHBhc3RlMChwbG90Zm9sZGVyLCBwYXRpZW50SUQsICJfIiwgc2FtcGxlMSwgIl8iLCBzYW1wbGUyLCAiXyIsIGJpbnNpemUsICIucG5nIiksIHBsb3QgPSBhcnJhbmdlcGxvdCwgd2lkdGggPSAxMSwgaGVpZ2h0ID0gOSwgZHBpID0gMzAwKQogICAKICAgZGZfY29tcGFyaXNvbiA8LSBkYXRhLmZyYW1lKFVuaXF1ZUlEID0gYyh1bmlxdWVJRCksIFBhdGllbnRJRCA9IGMocGF0aWVudElEKSwgQ0ZEX0lEID0gYyhzYW1wbGUxKSwgdHVtb3JETkFfSUQgPSBjKHNhbXBsZTIpLCBwZWFyc29uUiA9IGMoUiksIGNwYV9jZkROQSA9IGMoY3BhX3RvcCksIGNwYV90dW1vckROQSA9IGMoY3BhX2JvdHRvbSksIGNwYV90eXBlID0gYyhjcGEuY2FsYykpCiAgIHJldHVybihkZl9jb21wYXJpc29uKQp9CmBgYAoKIyBTYW1wbGUgYW5ub3RhdGlvbgpUaGUgc2FtcGxlIGFubm90YXRpb24gaXMgcmVhZCBmcm9tIHRoZSBgeGxzeCBmaWxlYC4KCmBgYHtyfQpzYW1wbGVfYW5ub3RhdGlvbiA8LSByZWFkX2V4Y2VsKCIvVXNlcnMvcm12cGFlbWUvRHJvcGJveCAoc3BlbGVtYW4gbGFiKS9CYXNlY2FtcC9DVlAvTFFCIHBlZGlhdHJpYyBwYXRpZW50cy9hbmFseXNpc19SVlAvc2FtcGxlX2Fubm90YXRpb24ueGxzeCIpCnNhbXBsZV9hbm5vdGF0aW9uIDwtIHNhbXBsZV9hbm5vdGF0aW9uICU+JSBmaWx0ZXIoY2ZETkFfZGF0YV9hdmFpbGFibGUgPT0gIlRSVUUiICYgdHVtb3JETkFfZGF0YV9hdmFpbGFibGUgPT0gIlRSVUUiKQpzYW1wbGVfYW5ub3RhdGlvbl9mdWxsIDwtIHNhbXBsZV9hbm5vdGF0aW9uCnNhbXBsZV9hbm5vdGF0aW9uIDwtIHNhbXBsZV9hbm5vdGF0aW9uICU+JSBmaWx0ZXIoaXMubmEoZmlsdGVyc2FtcGxlKSkKCnNhbXBsZV9hbm5vdGF0aW9uJFR1bW9yR3JvdXAgPC0gaWZlbHNlKAogICBzYW1wbGVfYW5ub3RhdGlvbiRUdW1vclR5cGUgJWluJSBjKCJFd2luZyBzYXJjb21hIiwgIm9zdGVvc2FyY29tYSIpLAogICAiYm9uZSB0dW1vciIsCiAgIGlmZWxzZSgKICAgICAgc2FtcGxlX2Fubm90YXRpb24kVHVtb3JUeXBlICVpbiUgYygKICAgICAgICAgIm5lcGhyb2JsYXN0b21hIiwKICAgICAgICAgIm1hbGlnbmFudCByaGFiZG9pZCB0dW1vciBvZiB0aGUga2lkbmV5IiwKICAgICAgICAgInJlbmFsIGNlbGwgY2FyY2lub21hIiwKICAgICAgICAgImtpZG5leSBzYXJjb21hIgogICAgICApLAogICAgICAia2lkbmV5IHR1bW9yIiwKICAgICAgaWZlbHNlKAogICAgICAgICBzYW1wbGVfYW5ub3RhdGlvbiRUdW1vclR5cGUgJWluJSBjKCJuZXVyb2JsYXN0b21hIiwgImdhbmdsaW9uZXVyb2JsYXN0b21hIiksCiAgICAgICAgICJuZXVyb2JsYXN0b21hIiwKICAgICAgICAgaWZlbHNlKAogICAgICAgICAgICBzYW1wbGVfYW5ub3RhdGlvbiRUdW1vclR5cGUgJWluJSBjKCJyaGFiZG9teW9zYXJjb21hIiksCiAgICAgICAgICAgICJyaGFiZG9teW9zYXJjb21hIiwgImJyYWluIHR1bW9yIgogICAgICAgICApCiAgICAgICkKICAgKQopCgoKc2FtcGxlX2Fubm90YXRpb24kVHVtb3JBYmJyZXYgPC0gc2FtcGxlX2Fubm90YXRpb24kVHVtb3JUeXBlCnNhbXBsZV9hbm5vdGF0aW9uJFR1bW9yQWJicmV2ICA8LSBnc3ViKCJFd2luZyBzYXJjb21hIiwgIkVXUyIsIHNhbXBsZV9hbm5vdGF0aW9uJFR1bW9yQWJicmV2KQpzYW1wbGVfYW5ub3RhdGlvbiRUdW1vckFiYnJldiAgPC0gZ3N1Yigib3N0ZW9zYXJjb21hIiwgIk9TIiwgc2FtcGxlX2Fubm90YXRpb24kVHVtb3JBYmJyZXYpCnNhbXBsZV9hbm5vdGF0aW9uJFR1bW9yQWJicmV2ICA8LSBnc3ViKCJhc3Ryb2N5dGljIHBpbG9jeXRvbWEiLCAiQVNQIiwgc2FtcGxlX2Fubm90YXRpb24kVHVtb3JBYmJyZXYpCnNhbXBsZV9hbm5vdGF0aW9uJFR1bW9yQWJicmV2ICA8LSBnc3ViKCJlcGVuZHltb21hIiwgIkVQQSIsIHNhbXBsZV9hbm5vdGF0aW9uJFR1bW9yQWJicmV2KQpzYW1wbGVfYW5ub3RhdGlvbiRUdW1vckFiYnJldiAgPC0gZ3N1YigiZ2FuZ2xpb2dsaW9tYSIsICJHR0EiLCBzYW1wbGVfYW5ub3RhdGlvbiRUdW1vckFiYnJldikKc2FtcGxlX2Fubm90YXRpb24kVHVtb3JBYmJyZXYgIDwtIGdzdWIoImdhbmdsaW9uZXVyb2JsYXN0b21hIiwgIkdOQSIsIHNhbXBsZV9hbm5vdGF0aW9uJFR1bW9yQWJicmV2KQpzYW1wbGVfYW5ub3RhdGlvbiRUdW1vckFiYnJldiAgPC0gZ3N1YigiZ2xpb2JsYXN0b21hIiwgIkdCQSIsIHNhbXBsZV9hbm5vdGF0aW9uJFR1bW9yQWJicmV2KQpzYW1wbGVfYW5ub3RhdGlvbiRUdW1vckFiYnJldiAgPC0gZ3N1YigiaGVtYW5naW9ibGFzdG9tYSIsICJIR0EiLCBzYW1wbGVfYW5ub3RhdGlvbiRUdW1vckFiYnJldikKc2FtcGxlX2Fubm90YXRpb24kVHVtb3JBYmJyZXYgIDwtIGdzdWIoImtpZG5leSBzYXJjb21hIiwgIktTIiwgc2FtcGxlX2Fubm90YXRpb24kVHVtb3JBYmJyZXYpCnNhbXBsZV9hbm5vdGF0aW9uJFR1bW9yQWJicmV2ICA8LSBnc3ViKCJtZW5pbmdpb21hIiwgIk1HQSIsIHNhbXBsZV9hbm5vdGF0aW9uJFR1bW9yQWJicmV2KQpzYW1wbGVfYW5ub3RhdGlvbiRUdW1vckFiYnJldiAgPC0gZ3N1YigibWFsaWduYW50IHJoYWJkb2lkIHR1bW9yIG9mIHRoZSBraWRuZXkiLCAiTVJUIiwgc2FtcGxlX2Fubm90YXRpb24kVHVtb3JBYmJyZXYpCnNhbXBsZV9hbm5vdGF0aW9uJFR1bW9yQWJicmV2ICA8LSBnc3ViKCJuZXBocm9ibGFzdG9tYSIsICJORkIiLCBzYW1wbGVfYW5ub3RhdGlvbiRUdW1vckFiYnJldikKc2FtcGxlX2Fubm90YXRpb24kVHVtb3JBYmJyZXYgIDwtIGdzdWIoIm5ldXJvYmxhc3RvbWEiLCAiTkJMIiwgc2FtcGxlX2Fubm90YXRpb24kVHVtb3JBYmJyZXYpCnNhbXBsZV9hbm5vdGF0aW9uJFR1bW9yQWJicmV2ICA8LSBnc3ViKCJyZW5hbCBjZWxsIGNhcmNpbm9tYSIsICJSQ0MiLCBzYW1wbGVfYW5ub3RhdGlvbiRUdW1vckFiYnJldikKc2FtcGxlX2Fubm90YXRpb24kVHVtb3JBYmJyZXYgIDwtIGdzdWIoInJoYWJkb215b3NhcmNvbWEiLCAiUk1TIiwgc2FtcGxlX2Fubm90YXRpb24kVHVtb3JBYmJyZXYpCnNhbXBsZV9hbm5vdGF0aW9uJFR1bW9yQWJicmV2ICA8LSBnc3ViKCJtZWR1bGxvYmxhc3RvbWEiLCAiTUJMIiwgc2FtcGxlX2Fubm90YXRpb24kVHVtb3JBYmJyZXYpCgpzYW1wbGVfYW5ub3RhdGlvbiRjZkROQV9ITVdfcmF0aW8gPC0gYXMubnVtZXJpYyhzYW1wbGVfYW5ub3RhdGlvbiRjZkROQV9wcmN0X2NvbmMpL2FzLm51bWVyaWMoc2FtcGxlX2Fubm90YXRpb24kSE1XX3ByY3RfY29uYykKc2FtcGxlX2Fubm90YXRpb24kY2ZETkFfSE1XX3JhdGlvIDwtIGFzLm51bWVyaWMoc2FtcGxlX2Fubm90YXRpb24kY2ZETkFfSE1XX3JhdGlvKQoKCnNhbXBsZV9hbm5vdGF0aW9uJHF1YWxpdHlfc2NvcmUgPC0gaWZlbHNlKHNhbXBsZV9hbm5vdGF0aW9uJGNmRE5BX0hNV19yYXRpbyA8IDEsICJsb3ciLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2Uoc2FtcGxlX2Fubm90YXRpb24kY2ZETkFfSE1XX3JhdGlvIDwgNSAmIHNhbXBsZV9hbm5vdGF0aW9uJGNmRE5BX0hNV19yYXRpbyA+IDEsICJtZWRpdW0iLCAiaGlnaCIpKQoKc2FtcGxlX2Fubm90YXRpb24kY2ZETkFfcHJjdCA8LSBhcy5udW1lcmljKHNhbXBsZV9hbm5vdGF0aW9uJGNmRE5BX3ByY3RfY29uYykvKGFzLm51bWVyaWMoc2FtcGxlX2Fubm90YXRpb24kSE1XX3ByY3RfY29uYykrYXMubnVtZXJpYyhzYW1wbGVfYW5ub3RhdGlvbiRjZkROQV9wcmN0X2NvbmMpKQpzYW1wbGVfYW5ub3RhdGlvbiRjZkROQV9ITVdfcmF0aW8gPC0gYXMubnVtZXJpYyhzYW1wbGVfYW5ub3RhdGlvbiRjZkROQV9ITVdfcmF0aW8pCgoKdHVtb3JTYW1wbGVzIDwtIHNhbXBsZV9hbm5vdGF0aW9uICU+JSBzZWxlY3QoVW5pcXVlSUQsIFBhdGllbnRJRCwgdHVtb3JETkFfSUQsIFR1bW9yVHlwZSx0dW1vckROQV9hc3NheSx0dW1vckROQV9hc3NheV9kZXRhaWwsIHR1bW9yRE5BX2Jpb21hdGVyaWFsLCBUdW1vckdyb3VwLGNmRE5BX0hNV19yYXRpbyApCmNvbG5hbWVzKHR1bW9yU2FtcGxlcykgPC0gYygiVW5pcXVlSUQiLCAiUGF0aWVudElEIiwgICJTYW1wbGVJRCIsICJUdW1vclR5cGUiLCAiYXNzYXkiLCAiYXNzYXlEZXRhaWwiLCAic291cmNlIiwgIlR1bW9yR3JvdXAiLCAiY2ZETkFfSE1XX3JhdGlvIikKdHVtb3JTYW1wbGVzJGJpb21hdGVyaWFsIDwtICJ0dW1vciBETkEiCgpjZkROQVNhbXBsZXMgPC0gIHNhbXBsZV9hbm5vdGF0aW9uICU+JSBzZWxlY3QoVW5pcXVlSUQsIFBhdGllbnRJRCwgQ0ZEX0lELCBUdW1vclR5cGUsdHVtb3JETkFfYXNzYXksdHVtb3JETkFfYXNzYXlfZGV0YWlsLCBDRkRfYmlvbWF0ZXJpYWwsIFR1bW9yR3JvdXAsIGNmRE5BX0hNV19yYXRpbykgCmNvbG5hbWVzKGNmRE5BU2FtcGxlcykgPC0gYygiVW5pcXVlSUQiLCAiUGF0aWVudElEIiwgICJTYW1wbGVJRCIsICJUdW1vclR5cGUiLCAiYXNzYXkiLCAiYXNzYXlEZXRhaWwiLCAic291cmNlIiwgIlR1bW9yR3JvdXAiLCAiY2ZETkFfSE1XX3JhdGlvIikKY2ZETkFTYW1wbGVzJGFzc2F5IDwtICJzV0dTIgpjZkROQVNhbXBsZXMkYXNzYXlEZXRhaWwgPC0gInNXR1MiCmNmRE5BU2FtcGxlcyRiaW9tYXRlcmlhbCA8LSAiY2ZETkEiCgpzYW1wbGVfYW5ub3RhdGlvbl9sb25nIDwtIGJpbmRfcm93cyh0dW1vclNhbXBsZXMsIGNmRE5BU2FtcGxlcykKYGBgCgojIEZlbXRvIFBVTFNFIGZpZ3VyZXMKYGBge3J9CmRmX2EgPC0gcmVhZF9jc3YoIi4vZGF0YS9GRU1UTy8yMDE5IDAzIDA2IDE4SCAwNk0gRWxlY3Ryb3BoZXJvZ3JhbS5jc3YiKQpkZl9hJHNhbXBsZSA8LSAiY2ZETkEvSE1XIHJhdGlvIFsxLDUpID0gNC4wMCIKI2RmX2Ekc2FtcGxlIDwtICJDRkQxODA2ODcyIgpjb2xuYW1lcyhkZl9hKSA8LSBjKCJTaXplIChicCkiLCAiUkZVIiwgInNhbXBsZSIpCgoKZGZfYiA8LSByZWFkX2NzdigiLi9kYXRhL0ZFTVRPLzIwMTkgMDMgMDYgMjJIIDM1TSBFbGVjdHJvcGhlcm9ncmFtLmNzdiIpCiNkZl9iJHNhbXBsZSA8LSAiQ0ZEMTYwMTY3NyIKZGZfYiRzYW1wbGUgPC0gImNmRE5BL0hNVyByYXRpbyBbNSziiJ4pID0gMzcuNTAiCmNvbG5hbWVzKGRmX2IpIDwtIGMoIlNpemUgKGJwKSIsICJSRlUiLCAic2FtcGxlIikKCmRmX2MgPC0gcmVhZF9jc3YoIi4vZGF0YS9GRU1UTy8yMDE5IDAzIDA2IDIzSCA0Mk0gRWxlY3Ryb3BoZXJvZ3JhbS5jc3YiKQojZGZfYyRzYW1wbGUgPC0gIkNGRDE2MDA4MDAiCmRmX2Mkc2FtcGxlIDwtICJjZkROQS9ITVcgcmF0aW8gWzAsMSkgPSAwLjc4Igpjb2xuYW1lcyhkZl9jKSA8LSBjKCJTaXplIChicCkiLCAiUkZVIiwgInNhbXBsZSIpCgpkZl9zaXplIDwtIHJiaW5kKGRmX2EsIGRmX2IsIGRmX2MpCmdncGxvdChkZl9zaXplLCBhZXMoeSA9IGBSRlVgLCB4ID0gYFNpemUgKGJwKWAsIGNvbCA9IHNhbXBsZSkpICsgZ2VvbV9saW5lKCkgKyBzY2FsZV94X2NvbnRpbnVvdXModHJhbnMgPSAibG9nMTAiLCBicmVha3MgPSBjKDEwMCwgMjUwLCA3MDAsIDI1MDAsIDYwMDApLCBsaW1pdHMgPSBjKDcwLDEyMDAwKSkgKyB0aGVtZV9idygpICsgZmFjZXRfd3JhcCh+c2FtcGxlLCBzY2FsZXMgPSAiZnJlZV95IikgKyB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCB2anVzdCA9IDAuNSwgaGp1c3QgPSAxKSkgKyBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSA3MDAsIGxpbmV0eXBlID0gImRhc2hlZCIsIGNvbG9yID0gImdyZXkiKSArIGd1aWRlcyhjb2wgPSBGQUxTRSkgKyBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gcWdfcGFsZXR0ZSgiVVNvcGVuIilbMTozXSkKZ2dzYXZlKCIuL3Bsb3RzL0ZQX3JhdGlvcy5wZGYiLCBwbG90ID0gZ2dwbG90Mjo6bGFzdF9wbG90KCksIGRwaSA9IDMwMCwgd2lkdGggPSA4LCBoZWlnaHQgPSA0KQpnZ3NhdmUoIi4vcGxvdHMvRlBfcmF0aW9zLnBuZyIsIHBsb3QgPSBnZ3Bsb3QyOjpsYXN0X3Bsb3QoKSwgZHBpID0gMzAwLCB3aWR0aCA9IDgsIGhlaWdodCA9IDQpCmdnc2F2ZSgiLi9wbG90cy9GUF9yYXRpb3Muc3ZnIiwgcGxvdCA9IGdncGxvdDI6Omxhc3RfcGxvdCgpLCBkcGkgPSAzMDAsIHdpZHRoID0gOCwgaGVpZ2h0ID0gNCkKYGBgCgoKIyBSZWFkaW5nIGluIGFsbCBkYXRhCldoaWxlIHJlYWRpbmcgaW4gdGhlIGRhdGEsIHRoZSBsb29wIG1ha2VzIGEgY29tcGFyYXRpdmUgZmlndXJlIGZvciBldmVyeSBjb21wYXJpc29uIGluIHNhbXBsZV9hbm5vdGF0aW9uLCBmb3IgZXhhbXBsZToKCiFbY29tcGFyaXNvbl0oL1VzZXJzL3JtdnBhZW1lL1JlcG9zL1JWUENWUDIwMTJfc1dHUy9wbG90cy9wYXRpZW50XzAzOV9DRkQxODAyMjgyX0ROQTA0NDA4NV8yMDBrYi5wbmcpCgpgYGB7cn0KCmlmICghZmlsZS5leGlzdHMoIi4vZGF0YS9jb21wYXJlQWxsLnRzdiIpKXsKICAgY2ZETkF2c1Rpc3N1ZSA8LSBkYXRhLmZyYW1lKCkKICAgI3NhbXBsZV9hbm5vdGF0aW9uIDwtIHNhbXBsZV9hbm5vdGF0aW9uICAlPiUgZmlsdGVyKFNhbXBsZU9yaWdpbiA9PSAiTUgiKQogICBmb3IgKHJvdyBpbiAxOm5yb3coc2FtcGxlX2Fubm90YXRpb24pKXsKICAgICAgc2FtcGxlMSA8LSBzYW1wbGVfYW5ub3RhdGlvbltyb3csXSRDRkRfSUQKICAgICAgc2FtcGxlMiA8LSBzYW1wbGVfYW5ub3RhdGlvbltyb3csXSR0dW1vckROQV9JRAogICAgICBwYXRpZW50SUQgPC0gIHNhbXBsZV9hbm5vdGF0aW9uW3JvdyxdJFBhdGllbnRJRAogICAgICB1bmlxdWVJRCA8LSAgc2FtcGxlX2Fubm90YXRpb25bcm93LF0kVW5pcXVlSUQKICAgICAgdGlzc3VlcGxhdGZvcm0gPC0gc2FtcGxlX2Fubm90YXRpb25bcm93LF0kdHVtb3JETkFfYXNzYXlfZGV0YWlsCiAgICAgIHR1bW9ydHlwZSA8LSBzYW1wbGVfYW5ub3RhdGlvbltyb3csXSRUdW1vclR5cGUKICAgICAgZGF0YWRpcjEgPC0gZGF0YWRpcl9zV0dTX2NmRE5BCiAgICAgIGlmIChzYW1wbGVfYW5ub3RhdGlvbltyb3csXSR0dW1vckROQV9hc3NheSA9PSAiYXJyYXlfQkUiKXsKICAgICAgICAgaW5wdXRfdHVtb3IgPSAiYXJyYXlfQkUiCiAgICAgICAgIGRhdGFkaXIyIDwtICBkYXRhZGlyX2FycmF5QkUKICAgICAgfSBlbHNlIGlmIChzYW1wbGVfYW5ub3RhdGlvbltyb3csXSR0dW1vckROQV9hc3NheSA9PSAiYXJyYXlfQ1oiKXsKICAgICAgICAgaW5wdXRfdHVtb3IgPSAiYXJyYXlfQ1oiCiAgICAgICAgIGRhdGFkaXIyIDwtICBkYXRhZGlyX2FycmF5Q1oKICAgICAgfSBlbHNlIGlmIChzYW1wbGVfYW5ub3RhdGlvbltyb3csXSR0dW1vckROQV9hc3NheSA9PSAiV0VTX0ZSIil7CiAgICAgICAgIGlucHV0X3R1bW9yID0gIldFU19GUiIKICAgICAgICAgZGF0YWRpcjIgPC0gIGRhdGFkaXJfV0VTCiAgICAgIH0gZWxzZSBpZiAoc2FtcGxlX2Fubm90YXRpb25bcm93LF0kdHVtb3JETkFfYXNzYXkgPT0gInNXR1MiKXsKICAgICAgICAgaW5wdXRfdHVtb3IgPSAic1dHUyIKICAgICAgICAgZGF0YWRpcjIgPC0gIGRhdGFkaXJfc1dHU190aXNzdWUKICAgICAgfQogICAgICBpZiAobGVuZ3RoKGRpcihkYXRhZGlyMiwgcGF0dGVybiA9IHNhbXBsZTIpID4gMCAgfCBsZW5ndGgoZGlyKGRhdGFkaXIxLCBwYXR0ZXJuID0gc2FtcGxlMSkgPiAwKSkpIHsKICAgICAgICAgdG1wIDwtIG1ha2VDTlZjb21wYXJpc29uKGRhdGFkaXIxLCBkYXRhZGlyMiwgc2FtcGxlMSwgc2FtcGxlMiwgcGF0aWVudElELCB1bmlxdWVJRCwgIjIwMGtiIiwgaW5wdXRfdHVtb3IsIHR1bW9ydHlwZSx0aXNzdWVwbGF0Zm9ybSkKICAgICAgICAgY2ZETkF2c1Rpc3N1ZSA8LSByYmluZChjZkROQXZzVGlzc3VlLCB0bXApCiAgICAgIH0KICAgICAgcHJpbnQocGFzdGUwKCJQcm9jZXNzZWQ6ICIsIHJvdywgIi8iLCBucm93KHNhbXBsZV9hbm5vdGF0aW9uKSkpCiAgIH0KICAgd3JpdGVfdHN2KGNmRE5BdnNUaXNzdWUsICIuL2RhdGEvY29tcGFyZUFsbC50c3YiKQp9IGVsc2UgewogICBjZkROQXZzVGlzc3VlICA8LSByZWFkX3RzdigiLi9kYXRhL2NvbXBhcmVBbGwudHN2IikKfQoKYSA8LSBjZkROQXZzVGlzc3VlICU+JSBzZWxlY3QoUGF0aWVudElELCAgVW5pcXVlSUQsIENGRF9JRCwgY3BhX2NmRE5BLCBwZWFyc29uUikKY29sbmFtZXMoYSkgPC0gYygiUGF0aWVudElEIiwgIlVuaXF1ZUlEIiwiU2FtcGxlSUQiLCAiQ1BBbSIsICJwZWFyc29uUiIpCmEkYmlvbWF0ZXJpYWwgPC0gImNmRE5BIgoKYiA8LSBjZkROQXZzVGlzc3VlICU+JSBzZWxlY3QoUGF0aWVudElELCBVbmlxdWVJRCwgdHVtb3JETkFfSUQsIGNwYV90dW1vckROQSwgcGVhcnNvblIgKQpjb2xuYW1lcyhiKSA8LSAgYygiUGF0aWVudElEIiwgIlVuaXF1ZUlEIiwiU2FtcGxlSUQiLCAiQ1BBbSIsICJwZWFyc29uUiIpCmIkYmlvbWF0ZXJpYWwgPC0gInR1bW9yIEROQSIKCmEgPC0gcmJpbmQoYSxiKQpzYW1wbGVfYW5ub3RhdGlvbl9sb25nIDwtIGxlZnRfam9pbihzYW1wbGVfYW5ub3RhdGlvbl9sb25nLCBhKQphIDwtIE5VTEwKYiA8LSBOVUxMCgoKY2ZETkF2c1Rpc3N1ZSA8LSBtZXJnZShzYW1wbGVfYW5ub3RhdGlvbiwgY2ZETkF2c1Rpc3N1ZSwgYnkgPSBjKCJQYXRpZW50SUQiLCAiVW5pcXVlSUQiLCAiUGF0aWVudElEIiwgIkNGRF9JRCIsICJ0dW1vckROQV9JRCIpKQoKCm5vcm1hbF9DUEEgPC0gcmVhZF9jc3YoIi4vZGF0YS9zV0dTX2hlYWx0aHkvQ1BBX2FsbC5jc3YiKSAlPiUgZHBseXI6OnNlbGVjdCgtQ1BBbSkgJT4lIG1lbHQoKSAKY29sbmFtZXMobm9ybWFsX0NQQSkgPC0gYygiQ0ZEX0lEIiwiY3BhX3R5cGUiLCAiY3BhX2NmRE5BIikKCm5vcm1hbF9DUEFtIDwtIHJlYWRfY3N2KCIuL2RhdGEvc1dHU19oZWFsdGh5L0NQQV9hbGwuY3N2IikgJT4lIGRwbHlyOjpzZWxlY3QoLUNQQSkgJT4lIG1lbHQoKSAKY29sbmFtZXMobm9ybWFsX0NQQW0pIDwtIGMoIkNGRF9JRCIsImNwYV90eXBlIiwgImNwYV9jZkROQSIpCm5vcm1hbF9DUEFtJGNwYV90dW1vckROQSA8LSBub3JtYWxfQ1BBJGNwYV9jZkROQQpub3JtYWxfQ1BBbSRUdW1vclR5cGUgPC0gImhlYWx0aHkiCm5vcm1hbF9DUEFtJENGRF9iaW9tYXRlcmlhbCA8LSAicGxhc21hIgpub3JtYWxfQ1BBbSRTYW1wbGVPcmlnaW4gPC0gIlVaRyIKbm9ybWFsX0NQQW0kY2ZETkFfSE1XX3JhdGlvIDwtIDAKY2ZETkF2c1Rpc3N1ZV93aXRoSGVhbHRoeSA8LSBiaW5kX3Jvd3MoY2ZETkF2c1Rpc3N1ZSwgbm9ybWFsX0NQQW0pCgpgYGAKCiMgQ2FsY3VsYXRpb24gb2YgdGhlIDElIEZEUiBmb3IgQ1BBbS9DUEEgdmFsdWVzCkEgbm9ybWFsIGRpc3RyaWJ1dGlvbiBpcyBmaXR0ZWQgdG8gdGhlIENQQW0gdmFsdWVzLCBhbmQgYmFzZWQgb24gdGhlIG1lYW4gYW5kIFNELCB0aGUgcW5vcm0oLjk5KSBpcyBkZXRlcm1pbmVkIHRvIG9idGFpbiB0aGUgMSUgRkRSIHJhdGlvLgoKYGBge3J9CmNhbGN1bGF0ZV9DUEFfRkRSIDwtIGZ1bmN0aW9uKGlucHV0LCB0aXRsZSApewogICBQID0gZWNkZihpbnB1dCAlPiUgcHVsbChjcGFfY2ZETkEpKSAKICAgcGxvdChQLCBtYWluID0gdGl0bGUpCiAgIAogICBsaWJyYXJ5KE1BU1MpCiAgIHggPC0gaW5wdXQgJT4lIHB1bGwoY3BhX2NmRE5BKQogICBmaXRfbm9ybWFsIDwtIGZpdGRpc3RyKHgsIGRlbnNmdW4gPSJub3JtYWwiKQogICBwYXJhIDwtIGZpdF9ub3JtYWwkZXN0aW1hdGUKICAgCiAgIGN1cnZlKGRub3JtKHgsIHBhcmFbMV0sIHBhcmFbMl0pLCBjb2wgPSAyLCBhZGQgPSBGQUxTRSwgeGxpbSA9IGMoMCwxLjUpKQogICBoaXN0KGlucHV0ICU+JSBwdWxsKGNwYV9jZkROQSksIHByb2I9VFJVRSwgYWRkID0gVFJVRSkKICAgCiAgIAogICBGRFJfQ1BBIDwtIHFub3JtKC45OSwgbWVhbiA9IHBhcmFbMV0sIHNkID0gcGFyYVsyXSkKICAgZGV0YWNoKCJwYWNrYWdlOk1BU1MiLCB1bmxvYWQgPSBUUlVFKQogICByZXR1cm4oRkRSX0NQQSkKfQoKRkRSX0NQQW0gPC0gY2FsY3VsYXRlX0NQQV9GRFIobm9ybWFsX0NQQW0sIHRpdGxlID0gImN1bXVsYXRpdmUgcGxvdCBDUEFtIikKRkRSX0NQQSA8LSBjYWxjdWxhdGVfQ1BBX0ZEUihub3JtYWxfQ1BBLCB0aXRsZSA9ICJjdW11bGF0aXZlIHBsb3QgQ1BBICIpCgojY2ZETkF2c1Rpc3N1ZSRDTkFfdHVtb3IgPC0gaWZlbHNlKGNmRE5BdnNUaXNzdWUkY3BhX3R1bW9yRE5BIDwgRkRSX0NQQW0sICJmbGF0IiwgIkNOQSIpCmNmRE5BdnNUaXNzdWUkQ05BX2NmRE5BIDwtIGlmZWxzZShjZkROQXZzVGlzc3VlJGNwYV9jZkROQSA8IEZEUl9DUEFtLCAiZmxhdCIsICJDTkEiKQojY2ZETkF2c1Rpc3N1ZSRDTkFfYWxsIDwtIHBhc3RlMChjZkROQXZzVGlzc3VlJENOQV90dW1vciwgIi0iLCBjZkROQXZzVGlzc3VlJENOQV9jZkROQSkKYGBgCgpUaGUgMSUgRkRSIGZvciBDUEFtIGlzIGByIEZEUl9DUEFtYCBhbmQgdGhlIDElIEZEUiBmb3IgQ1BBIGlzIGByIEZEUl9DUEFgLiAKCmBgYHtyfQpsaWJyYXJ5KGdlaWdlcikKYmluc2l6ZSA9ICIyMDBrYiIKCm1ha2VMb2cyY29tcGFyaXNvbiA8LSBmdW5jdGlvbihkYXRhZGlyMSwgZGF0YWRpcjIsIHNhbXBsZTEsIHNhbXBsZTIsIHBhdGllbnRJRCl7CiAgIAogICBwcmludChwYXN0ZTAoImNmRE5BIHNhbXBsZTogIiwgc2FtcGxlMSkpCiAgIHByaW50KHBhc3RlMCgidHVtb3JETkEgc2FtcGxlOiAiLCBzYW1wbGUyKSkKICAgcHJpbnQocGFzdGUwKCJiaW5zaXplOiAiLCBiaW5zaXplKSkKICAgCiAgIAogICB0bXBfQSA8LSByZWFkX3RzdihwYXN0ZTAoZGF0YWRpcjEsIHN0cl9zdWJzZXQoZGlyKGRhdGFkaXIxLCBwYXR0ZXJuID0gc2FtcGxlMSksICJzZWdtZW50c19wZXJfMjAwa2JfbWFzay50c3YiKSksIGNvbF90eXBlcyA9IGMoImZkZGQiKSwKICAgICAgICAgICAgICAgICAgICAgY29sX25hbWVzID0gYygiY2hyIiwgInN0YXJ0IiwgImVuZCIsICJyYXRpb19jZkROQSIpLCBza2lwID0gMSkKICAgdG1wX0EgPC0gdG1wX0EgJT4lIGZpbHRlcighY2hyICVpbiUgYygiWCIsICJZIiwgIjIzIiwgIjI0IikpIAogICAKICAgCiAgIHNlZ3NfQSA8LSByZWFkX3RzdihwYXN0ZTAoZGF0YWRpcjEsIHN0cl9zdWJzZXQoZGlyKGRhdGFkaXIxLCBwYXR0ZXJuID0gc2FtcGxlMSksICJzZWdtZW50c19tYXNrLmJlZCIpKSwgY29sX3R5cGVzID0gYygiZmRkZGQiKSwKICAgICAgICAgICAgICAgICAgICAgIGNvbF9uYW1lcyA9IGMoImNociIsICJzdGFydCIsICJlbmQiLCAicmF0aW8iLCAienNjb3JlIikpCiAgIHNlZ3NfQSA8LSBzZWdzX0EgJT4lIGZpbHRlcighY2hyICVpbiUgYygiWCIsICJZIiwgIjIzIiwgIjI0IikpCiAgIAogICB0bXBfQiA8LSByZWFkX3RzdihwYXN0ZTAoZGF0YWRpcjIsIHN0cl9zdWJzZXQoZGlyKGRhdGFkaXIyLCBwYXR0ZXJuID0gc2FtcGxlMiksICJzZWdtZW50c19wZXJfMjAwa2JfbWFzay50c3YiKSksIGNvbF90eXBlcyA9IGMoImZkZGQiKSwKICAgICAgICAgICAgICAgICAgICAgY29sX25hbWVzID0gYygiY2hyIiwgInN0YXJ0IiwgImVuZCIsICJyYXRpb190dW1vciIpLCBza2lwID0gMSkKICAgdG1wX0IgPC0gdG1wX0IgJT4lIGZpbHRlcighY2hyICVpbiUgYygiWCIsICJZIiwgIjIzIiwgIjI0IikpIAogICAKICAgaWYgKHR1bW9yX2lucHV0ID09ICJhcnJheV9CRSIgfCB0dW1vcl9pbnB1dCA9PSAiYXJyYXlfQ1oiIHwgdHVtb3JfaW5wdXQgPT0gIldFU19GUiIpewogICAgICBzZWdzX0IgPC0gcmVhZF90c3YocGFzdGUwKGRhdGFkaXIyLCIvIixzYW1wbGUyLCJfIiwgYmluc2l6ZSwgIl9zZWdtZW50cy50c3YiKSwgY29sX3R5cGVzID0gYygiZmRkZCIpLAogICAgICAgICAgICAgICAgICAgICAgICAgY29sX25hbWVzID0gYygiY2hyIiwgInN0YXJ0IiwgImVuZCIsICJyYXRpbyIpLCBza2lwID0gMSkKICAgICAgCiAgICAgIHNlZ3NfQiA8LSBzZWdzX0IgJT4lIGZpbHRlcighY2hyICVpbiUgYygiWCIsICJZIiwgIjIzIiwgIjI0IikpIAogICB9IGVsc2UgaWYgKHR1bW9yX2lucHV0ID09ICJzV0dTIil7CiAgICAgIHNlZ3NfQiA8LSByZWFkX3RzdihwYXN0ZTAoZGF0YWRpcjIsIHN0cl9zdWJzZXQoZGlyKGRhdGFkaXIyLCBwYXR0ZXJuID0gc2FtcGxlMiksICJzZWdtZW50c19tYXNrLmJlZCIpKSwgY29sX3R5cGVzID0gYygiZmRkZGQiKSwKICAgICAgICAgICAgICAgICAgICAgICAgIGNvbF9uYW1lcyA9IGMoImNociIsICJzdGFydCIsICJlbmQiLCAicmF0aW8iLCAienNjb3JlIikpCiAgICAgIHNlZ3NfQiA8LSBzZWdzX0IgJT4lIGZpbHRlcighY2hyICVpbiUgYygiWCIsICJZIiwgIjIzIiwgIjI0IikpIAogICB9CiAgICMgCiAgICMgc2Vnc19CIDwtIHJlYWRfdHN2KHBhc3RlMChkYXRhZGlyMiwiLyIsc2FtcGxlMiwiXyIsIGJpbnNpemUsICJfc2VnbWVudHMudHN2IiksIGNvbF90eXBlcyA9IGMoImZkZGQiKSwKICAgIyAgICAgICAgICAgICAgICAgICAgICBjb2xfbmFtZXMgPSBjKCJjaHIiLCAic3RhcnQiLCAiZW5kIiwgInJhdGlvIiksIHNraXAgPSAxKQogICAjIAogICAjIHNlZ3NfQiA8LSBzZWdzX0IgJT4lIGZpbHRlcighY2hyICVpbiUgYygiWCIsICJZIiwgIjIzIiwgIjI0IikpIAogICAKICAgdG1wIDwtIGlubmVyX2pvaW4odG1wX0EsIHRtcF9CKQogICB0bXAkYWJzbG9nMmRpZmZQZXJCaW4gPC0gYWJzKHRtcCRyYXRpb190dW1vciAtIHRtcCRyYXRpb19jZkROQSkKICAgc2VnZGlmZiA8LSBucm93KHNlZ3NfQikgLSBucm93KHNlZ3NfQSkKICAgCiAgIG1lYW5EaWZmUGVyQmluIDwtIG1lYW4odG1wJGFic2xvZzJkaWZmUGVyQmluKnNlZ2RpZmYpCiAgIGN1bXVsRGlmZlBlckJpbiA8LSBzdW0odG1wJGFic2xvZzJkaWZmUGVyQmluKnNlZ2RpZmYpCiAgIGRhdGEuZnJhbWUoY2ZETkFfSUQgPSBzYW1wbGUxLCB0dW1vckROQV9JRCA9IHNhbXBsZTIsIG1lYW5fYWJzX2RpZmZfbG9nMiA9IG1lYW5EaWZmUGVyQmluLCBjdW11bERpZmZQZXJCaW4gPSBjdW11bERpZmZQZXJCaW4pCn0KCm1ha2VCaW5zQ29tcGFyaXNvbiA8LSBmdW5jdGlvbihkYXRhZGlyMSwgZGF0YWRpcjIsIHNhbXBsZTEsIHNhbXBsZTIsIHBhdGllbnRJRCl7CiAgIAogICBiaW5zX3RvcCA8LSByZWFkX3RzdihwYXN0ZTAoZGF0YWRpcjEsIHN0cl9zdWJzZXQoZGlyKGRhdGFkaXIxLCBwYXR0ZXJuID0gc2FtcGxlMSksICJiaW5zX21hc2siKSksIGNvbF90eXBlcyA9IGMoImZkZD9kIiksCiAgICAgICAgICAgICAgICAgICAgICAgIGNvbF9uYW1lcyA9IGMoImNociIsICJzdGFydCIsICJlbmQiLCAiaWQiLCAicmF0aW8iKSwgc2tpcCA9IDEpCiAgIGJpbnNfdG9wIDwtIGJpbnNfdG9wICU+JSBmaWx0ZXIoIWNociAlaW4lIGMoIlgiLCAiWSIsICIyMyIsICIyNCIpKSU+JSBtdXRhdGUoU2FtcGxlSUQgPSBzYW1wbGUxKQogICAKICAgaWYgKHR1bW9yX2lucHV0ID09ICJhcnJheV9CRSIgfCB0dW1vcl9pbnB1dCA9PSAiYXJyYXlfQ1oiIHwgdHVtb3JfaW5wdXQgPT0gIldFU19GUiIgKXsKICAgICAgYmluc19ib3R0b20gPC0gIHJlYWRfdHN2KHBhc3RlMChkYXRhZGlyMiwiLyIsc2FtcGxlMiwiXyIsIGJpbnNpemUsICIudHN2IiksIGNvbF90eXBlcyA9IGMoImZkZGQiKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbF9uYW1lcyA9IGMoImNociIsICJzdGFydCIsICJlbmQiLCAicmF0aW8iKSkKICAgICAgYmluc19ib3R0b20gPC0gYmluc19ib3R0b20gJT4lIGZpbHRlcighY2hyICVpbiUgYygiWCIsICJZIiwgIjIzIiwgIjI0IikpICU+JSBtdXRhdGUoU2FtcGxlSUQgPSBzYW1wbGUyKQogICAgICBiaW5zX2JvdHRvbSRjaHIgPC0gZmFjdG9yKGJpbnNfYm90dG9tJGNociwgbGV2ZWxzID0gY2hyX29yZGVyKQogICAgICAKICAgfSBlbHNlIGlmICh0dW1vcl9pbnB1dCA9PSAic1dHUyIpewogICAgICBiaW5zX2JvdHRvbSA8LSAgcmVhZF90c3YocGFzdGUwKGRhdGFkaXIyLCBzdHJfc3Vic2V0KGRpcihkYXRhZGlyMiwgcGF0dGVybiA9IHNhbXBsZTIpLCAiYmluc19tYXNrIikpLCBjb2xfdHlwZXMgPSBjKCJmZGQ/ZCIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sX25hbWVzID0gYygiY2hyIiwgInN0YXJ0IiwgImVuZCIsICJpZCIsICJyYXRpbyIpKQogICAgICBiaW5zX2JvdHRvbSA8LSBiaW5zX2JvdHRvbSAlPiUgZmlsdGVyKCFjaHIgJWluJSBjKCJYIiwgIlkiLCAiMjMiLCAiMjQiKSklPiUgbXV0YXRlKFNhbXBsZUlEID0gc2FtcGxlMikgJT4lIHNlbGVjdCgtaWQpCiAgICAgIGJpbnNfYm90dG9tJGNociA8LSBmYWN0b3IoYmluc19ib3R0b20kY2hyLCBsZXZlbHMgPSBjaHJfb3JkZXIpCiAgIH0KICAgCiAgIAogICBjb3JwbG90X2RmX2JpbnMgPC0gZnVsbF9qb2luKGJpbnNfdG9wLCBiaW5zX2JvdHRvbSwgYnkgPSBjKCJjaHIiLCAic3RhcnQiLCAiZW5kIikpICU+JSBzZWxlY3QoLWNociwgLXN0YXJ0LCAtZW5kKQogICBjb2xuYW1lcyhjb3JwbG90X2RmX2JpbnMpIDwtIGMoImlkIiwgIkwyUl9jZkROQSIsICJDRkRfSUQiLCAiTDJSX3R1bW9yRE5BIiwgInR1bW9yRE5BX0lEIikKICAgY29ycGxvdF9kZl9iaW5zJFBhdGllbnRJRCA8LSBwYXRpZW50SUQKICAgY29ycGxvdF9kZl9iaW5zCiAgIAp9CgoKaWYgKCFmaWxlLmV4aXN0cygiLi9kYXRhL2FsbGRpZmZzLnRzdiIpKXsKICAgYWxsZGlmZnMgPC0gZGF0YS5mcmFtZSgpCiAgIEwyUmNvbXBhcmlzb24gPC0gZGF0YS5mcmFtZSgpCiAgIGZvciAocm93IGluIDE6bnJvdyhzYW1wbGVfYW5ub3RhdGlvbikpewogICAgICBzYW1wbGUxIDwtIHNhbXBsZV9hbm5vdGF0aW9uW3JvdyxdJENGRF9JRAogICAgICBzYW1wbGUyIDwtIHNhbXBsZV9hbm5vdGF0aW9uW3JvdyxdJHR1bW9yRE5BX0lECiAgICAgIHBhdGllbnRJRCA8LSAgc2FtcGxlX2Fubm90YXRpb25bcm93LF0kUGF0aWVudElECiAgICAgIHRpc3N1ZXBsYXRmb3JtIDwtIHNhbXBsZV9hbm5vdGF0aW9uW3JvdyxdJHR1bW9yRE5BX2Fzc2F5X2RldGFpbAogICAgICB0dW1vcnR5cGUgPC0gc2FtcGxlX2Fubm90YXRpb25bcm93LF0kVHVtb3JUeXBlCiAgICAgIGRhdGFkaXIxIDwtIGRhdGFkaXJfc1dHU19jZkROQQogICAgICBpZiAoc2FtcGxlX2Fubm90YXRpb25bcm93LF0kdHVtb3JETkFfYXNzYXkgPT0gImFycmF5X0JFIil7CiAgICAgICAgIHR1bW9yX2lucHV0ID0gImFycmF5X0JFIgogICAgICAgICBkYXRhZGlyMiA8LSAgZGF0YWRpcl9hcnJheUJFCiAgICAgIH0gZWxzZSBpZiAoc2FtcGxlX2Fubm90YXRpb25bcm93LF0kdHVtb3JETkFfYXNzYXkgPT0gImFycmF5X0NaIil7CiAgICAgICAgIHR1bW9yX2lucHV0ID0gImFycmF5X0NaIgogICAgICAgICBkYXRhZGlyMiA8LSAgZGF0YWRpcl9hcnJheUNaCiAgICAgIH0gZWxzZSBpZiAoc2FtcGxlX2Fubm90YXRpb25bcm93LF0kdHVtb3JETkFfYXNzYXkgPT0gIldFU19GUiIpewogICAgICAgICB0dW1vcl9pbnB1dCA9ICJXRVNfRlIiCiAgICAgICAgIGRhdGFkaXIyIDwtICBkYXRhZGlyX1dFUwogICAgICB9IGVsc2UgaWYgKHNhbXBsZV9hbm5vdGF0aW9uW3JvdyxdJHR1bW9yRE5BX2Fzc2F5ID09ICJzV0dTIil7CiAgICAgICAgIHR1bW9yX2lucHV0ID0gInNXR1MiCiAgICAgICAgIGRhdGFkaXIyIDwtICBkYXRhZGlyX3NXR1NfdGlzc3VlCiAgICAgIH0KICAgICAgaWYgKGxlbmd0aChkaXIoZGF0YWRpcjIsIHBhdHRlcm4gPSBzYW1wbGUyKSA+IDAgIHwgbGVuZ3RoKGRpcihkYXRhZGlyMSwgcGF0dGVybiA9IHNhbXBsZTEpID4gMCkpKSB7CiAgICAgICAgIHRtcCA8LSBtYWtlTG9nMmNvbXBhcmlzb24oZGF0YWRpcjEsIGRhdGFkaXIyLCBzYW1wbGUxLCBzYW1wbGUyLCBwYXRpZW50SUQpCiAgICAgICAgIHRtcF9MMlIgPC0gbWFrZUJpbnNDb21wYXJpc29uKGRhdGFkaXIxLCBkYXRhZGlyMiwgc2FtcGxlMSwgc2FtcGxlMiwgcGF0aWVudElEKQogICAgICAgICBhbGxkaWZmcyA8LSByYmluZChhbGxkaWZmcywgdG1wKQogICAgICAgICBMMlJjb21wYXJpc29uIDwtIHJiaW5kKEwyUmNvbXBhcmlzb24sIHRtcF9MMlIpCiAgICAgIH0KICAgICAgcHJpbnQocGFzdGUwKCJQcm9jZXNzZWQ6ICIsIHJvdywgIi8iLCBucm93KHNhbXBsZV9hbm5vdGF0aW9uKSkpCiAgIH0KICAgd3JpdGVfdHN2KGFsbGRpZmZzLCAiLi9kYXRhL2FsbGRpZmZzLnRzdiIpCiAgIHdyaXRlX3RzdihMMlJjb21wYXJpc29uLCAiLi9kYXRhL0wyUi50c3YiKQp9IGVsc2UgewogICBhbGxkaWZmcyAgPC0gcmVhZF90c3YoIi4vZGF0YS9hbGxkaWZmcy50c3YiKQogICBMMlJjb21wYXJpc29uIDwtIHJlYWRfdHN2KCIuL2RhdGEvTDJSLnRzdiIpCn0KCmNmRE5BdnNUaXNzdWUgPC0gbGVmdF9qb2luKGNmRE5BdnNUaXNzdWUsIGFsbGRpZmZzLCBieSA9IGMoIkNGRF9JRCIgPSAiY2ZETkFfSUQiLCAidHVtb3JETkFfSUQiID0gInR1bW9yRE5BX0lEIikpCkwyUmNvbXBhcmlzb24gPC0gbGVmdF9qb2luKGNmRE5BdnNUaXNzdWUsIEwyUmNvbXBhcmlzb24sIGJ5ID0gYygiQ0ZEX0lEIiA9ICJDRkRfSUQiLCAidHVtb3JETkFfSUQiID0gInR1bW9yRE5BX0lEIiwgIlBhdGllbnRJRCIgPSAiUGF0aWVudElEIikpCgpgYGAKCgpgYGB7cn0KaWYgKCFmaWxlLmV4aXN0cygiLi9kYXRhL21lcmdlZF9zZWdtZW50cy50c3YiKSl7CiAgIHJlYWRfc2VnbWVudHMgPC0gZnVuY3Rpb24oZGF0YWRpcil7CiAgICAgIGZpbGVzPC1saXN0LmZpbGVzKGMoZGF0YWRpcikscmVjdXJzaXZlPVRSVUUpCiAgICAgIGZpbGVzPC1maWxlc1tncmVwKCJlZ21lbnRzX3Blcl9bMC05XStrYl9tYXNrIiwgZmlsZXMpXQogICAgICB0bXBfaGVhdG1hcCA8LSBkYXRhLmZyYW1lKCkKICAgICAgZm9yKGkgaW4gMTpsZW5ndGgoZmlsZXMpKXsKICAgICAgICAgbmFtZV9zYW1wbGUgPC0gZ3N1YigiX3NlZ21lbnRzX3Blcl9bMC05XStrYl9tYXNrLnRzdiIsICIiLCBmaWxlc1tpXSkKICAgICAgICAgcHJpbnQobmFtZV9zYW1wbGUpCiAgICAgICAgIHRtcCA8LSAgcmVhZF90c3YocGFzdGUwKGRhdGFkaXIsZmlsZXNbaV0pLCBjb2xfdHlwZXMgPSBjKCJmZGRkIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgY29sX25hbWVzID0gYygiY2hyIiwgInN0YXJ0IiwgImVuZCIsICJyYXRpbyIpLCBza2lwID0gMSkKICAgICAgICAgCiAgICAgICAgIGNvbG5hbWVzKHRtcCk8LSBjKCJjaHIiLCAic3RhcnQiLCAiZW5kIiwgInJhdGlvIikKICAgICAgICAgdG1wIDwtIHRtcCAlPiUgZmlsdGVyKCFjaHIgJWluJSBjKCJYIiwgIlkiLCAiMjMiLCAiMjQiKSkKICAgICAgICAgdG1wJFNhbXBsZUlEIDwtIG5hbWVfc2FtcGxlCiAgICAgICAgIHRtcCRtZWFuTG9nMiA8LSBnZXQuY3BhLm1vZGlmaWVkMih0bXApCiAgICAgICAgIGlmIChucm93KHRtcF9oZWF0bWFwKSA9PSAwKXsKICAgICAgICAgICAgdG1wX2hlYXRtYXAgPC0gdG1wCiAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgIHRtcF9oZWF0bWFwIDwtIHJiaW5kKHRtcF9oZWF0bWFwLCB0bXApCiAgICAgICAgIH0KICAgICAgfQogICAgICByZXR1cm4odG1wX2hlYXRtYXApCiAgIH0KICAgZGZfaGVhdG1hcF9pbml0IDwtIGRhdGEuZnJhbWUoKQogICBkZl9oZWF0bWFwX2luaXQgPC0gcmJpbmQoZGZfaGVhdG1hcF9pbml0LCByZWFkX3NlZ21lbnRzKGRhdGFkaXJfc1dHU19jZkROQSkpCiAgIGRmX2hlYXRtYXBfaW5pdCA8LSByYmluZChkZl9oZWF0bWFwX2luaXQsIHJlYWRfc2VnbWVudHMoZGF0YWRpcl9XRVMpKQogICBkZl9oZWF0bWFwX2luaXQgPC0gcmJpbmQoZGZfaGVhdG1hcF9pbml0LCByZWFkX3NlZ21lbnRzKGRhdGFkaXJfc1dHU190aXNzdWUpKQogICBkZl9oZWF0bWFwX2luaXQgPC0gcmJpbmQoZGZfaGVhdG1hcF9pbml0LCByZWFkX3NlZ21lbnRzKGRhdGFkaXJfYXJyYXlDWikpCiAgIGRmX2hlYXRtYXBfaW5pdCA8LSByYmluZChkZl9oZWF0bWFwX2luaXQsIHJlYWRfc2VnbWVudHMoZGF0YWRpcl9hcnJheUJFKSkKICAgCiAgIGRmX2hlYXRtYXBfaGVhbHRoeSA8LSBkYXRhLmZyYW1lKCkKICAgZGZfaGVhdG1hcF9oZWFsdGh5IDwtIHJiaW5kKGRmX2hlYXRtYXBfaGVhbHRoeSwgcmVhZF9zZWdtZW50cyhkYXRhZGlyX2hlYWx0aHkpKQogICB3cml0ZV90c3YoZGZfaGVhdG1hcF9pbml0LCAiLi9kYXRhL21lcmdlZF9zZWdtZW50cy50c3YiKQogICB3cml0ZV90c3YoZGZfaGVhdG1hcF9oZWFsdGh5LCAiLi9kYXRhL21lcmdlZF9zZWdtZW50c19oZWFsdGh5LnRzdiIpCn0gZWxzZSB7CiAgIGRmX2hlYXRtYXBfaW5pdCA8LSByZWFkX3RzdigiLi9kYXRhL21lcmdlZF9zZWdtZW50cy50c3YiKQogICBkZl9oZWF0bWFwX2hlYWx0aHkgPC0gcmVhZF90c3YoIi4vZGF0YS9tZXJnZWRfc2VnbWVudHNfaGVhbHRoeS50c3YiKQp9CgpkZl9oZWF0bWFwX2luaXQkU2FtcGxlSUQgPC0gZ3N1YigiXy4qIiwgIiIsIGRmX2hlYXRtYXBfaW5pdCRTYW1wbGVJRCkKZGZfaGVhdG1hcF9pbml0IDwtIGRmX2hlYXRtYXBfaW5pdCAKCmEgPC0gZGZfaGVhdG1hcF9pbml0ICU+JSBkaXN0aW5jdChtZWFuTG9nMiwgU2FtcGxlSUQpCmNmRE5BdnNUaXNzdWUgPC0gbGVmdF9qb2luKGNmRE5BdnNUaXNzdWUsIGEsIGJ5ID0gYygiQ0ZEX0lEIiA9ICJTYW1wbGVJRCIpKQpjZkROQXZzVGlzc3VlIDwtIGxlZnRfam9pbihjZkROQXZzVGlzc3VlLCBhLCBieSA9IGMoInR1bW9yRE5BX0lEIiA9ICJTYW1wbGVJRCIpKQpjZkROQXZzVGlzc3VlJGRlbHRhTG9nMiA8LSBhYnMoY2ZETkF2c1Rpc3N1ZSRtZWFuTG9nMi54IC0gY2ZETkF2c1Rpc3N1ZSRtZWFuTG9nMi55KQphIDwtIE5VTEwKCmBgYAoKCiMgRGlmZmVyZW5jZSBwbG90IGJldHdlZW4gY2ZETkEgYW5kIHR1bW9yIEROQQpgYGB7cn0KdHVtb3IgPSAibmVwaHJvYmxhc3RvbWEiCm1ha2VCYXJUdW1vcnZzY2ZETkEgPC0gZnVuY3Rpb24odHVtb3IpewogICBiYXJQbG90IDwtIGRmX2hlYXRtYXBfaW5pdAogICBzYW1wbGVGaWx0X2EgPC0gc2FtcGxlX2Fubm90YXRpb25fbG9uZyAlPiUgZmlsdGVyKGNmRE5BX0hNV19yYXRpbyA+IDUpICU+JSBmaWx0ZXIoVHVtb3JUeXBlID09IHR1bW9yICYgYmlvbWF0ZXJpYWwgPT0gImNmRE5BIikgJT4lIHB1bGwoU2FtcGxlSUQpCiAgIGJhclBsb3RfYSA8LSBiYXJQbG90ICU+JSBmaWx0ZXIoU2FtcGxlSUQgJWluJSBzYW1wbGVGaWx0X2EpCiAgIGJhclBsb3RfYSA8LSBiYXJQbG90X2EgJT4lIGdyb3VwX2J5KGNociwgc3RhcnQpICU+JQogICAgICBzdW1tYXJpc2UobWVhbiA9IG1lYW4ocmF0aW8sIG5hLnJtID0gVFJVRSksCiAgICAgICAgICAgICAgICBzZCA9IHNkKHJhdGlvLCBuYS5ybSA9IFRSVUUpLAogICAgICAgICAgICAgICAgbiA9IG4oKSkgJT4lCiAgICAgIG11dGF0ZShzZSA9IHNkIC8gc3FydChuKSwKICAgICAgICAgICAgIGxvd2VyLmNpID0gbWVhbiAtIHF0KDEgLSAoMC4wNSAvIDIpLCBuIC0gMSkgKiBzZSwKICAgICAgICAgICAgIHVwcGVyLmNpID0gbWVhbiArIHF0KDEgLSAoMC4wNSAvIDIpLCBuIC0gMSkgKiBzZSkgCiAgIGJhclBsb3RfYSRiaW9tYXRlcmlhbCA8LSAiY2ZETkEiCiAgIAogICBzYW1wbGVGaWx0X2IgPC0gc2FtcGxlX2Fubm90YXRpb25fbG9uZyAlPiUgZmlsdGVyKGNmRE5BX0hNV19yYXRpbyA+IDEpICU+JSBmaWx0ZXIoVHVtb3JUeXBlID09IHR1bW9yICYgYmlvbWF0ZXJpYWwgPT0gInR1bW9yIEROQSIpICU+JSBwdWxsKFNhbXBsZUlEKQogICBiYXJQbG90X2IgPC0gYmFyUGxvdCAlPiUgZmlsdGVyKFNhbXBsZUlEICVpbiUgc2FtcGxlRmlsdF9iKQogICBiYXJQbG90X2IgPC0gYmFyUGxvdF9iICU+JSBncm91cF9ieShjaHIsIHN0YXJ0KSAlPiUKICAgICAgc3VtbWFyaXNlKG1lYW4gPSBtZWFuKHJhdGlvLCBuYS5ybSA9IFRSVUUpLAogICAgICAgICAgICAgICAgc2QgPSBzZChyYXRpbywgbmEucm0gPSBUUlVFKSwKICAgICAgICAgICAgICAgIG4gPSBuKCkpICU+JQogICAgICBtdXRhdGUoc2UgPSBzZCAvIHNxcnQobiksCiAgICAgICAgICAgICBsb3dlci5jaSA9IG1lYW4gLSBxdCgxIC0gKDAuMDUgLyAyKSwgbiAtIDEpICogc2UsCiAgICAgICAgICAgICB1cHBlci5jaSA9IG1lYW4gKyBxdCgxIC0gKDAuMDUgLyAyKSwgbiAtIDEpICogc2UpIAogICBiYXJQbG90X2IkYmlvbWF0ZXJpYWwgPC0gInR1bW9yIEROQSIKICAgCiAgIAogICBnZ3Bsb3QoKSArIAogICAgICB0aGVtZV9idygpICsgCiAgICAgICMgbGFicyh0aXRsZSA9IHBhc3RlMChwYXRpZW50SUQsICIgLSAiLCB0aXNzdWVwbGF0Zm9ybSwgIiB0aXNzdWUgLSAiLCBzYW1wbGUyLCAiIC0gIixjcGEuY2FsYywgIjogIiwgY3BhX2JvdHRvbSwgIiAtICIsIHR1bW9ydHlwZSksIHkgPSAibG9nMihyYXRpbykiKSArCiAgICAgIGdlb21fYmFyKGRhdGEgPSBiYXJQbG90X2EsIGFlcyh4ID0gc3RhcnQsIHkgPSBtZWFuLCBjb2wgPSBiaW9tYXRlcmlhbCwgZmlsbCA9IGJpb21hdGVyaWFsKSwgc3RhdCA9ICJpZGVudGl0eSIsIHBvc2l0aW9uID0gImRvZGdlIiwgYWxwaGEgPSAxLCBzaXplID0gMCkgKwogICAgICBnZW9tX2JhcihkYXRhID0gYmFyUGxvdF9iLCBhZXMoeCA9IHN0YXJ0LCB5ID0gbWVhbiwgY29sID0gYmlvbWF0ZXJpYWwsIGZpbGwgPSBiaW9tYXRlcmlhbCksIHN0YXQgPSAiaWRlbnRpdHkiLCBwb3NpdGlvbiA9ICJkb2RnZSIsIGFscGhhID0gMC41LCBzaXplID0gMCkgKwogICAgICBsaW1zKHkgPSBjKC0uNiwuNikpKyAKICAgICAgbGFicyh0aXRsZSA9IHBhc3RlMCh0dW1vciwgIiAobiA9ICIsIGxlbmd0aChzYW1wbGVGaWx0X2IpLCIpIiksIHkgPSAibWVhbiBvZiBsb2cyKHJhdGlvKSBhY3Jvc3MgYWxsIHNhbXBsZXMiKSsKICAgICAgdGhlbWUocGFuZWwuc3BhY2luZy54ID0gdW5pdCgwLCAibGluZXMiKSwKICAgICAgICAgICAgcGFuZWwuc3BhY2luZy55ID0gdW5pdCgwLCAibGluZXMiKSwKICAgICAgICAgICAgYXhpcy50aXRsZS54ID0gIGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgICAgYXhpcy50ZXh0LnggPSAgZWxlbWVudF9ibGFuaygpLAogICAgICAgICAgICBheGlzLnRpY2tzLnggPSAgZWxlbWVudF9ibGFuaygpLAogICAgICAgICAgICBzdHJpcC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGNvbG9yID0gIndoaXRlIiwgZmlsbCA9ICJ3aGl0ZSIpLAogICAgICAgICAgICBwYW5lbC5ncmlkLm1ham9yID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgICAgICBwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgICAgICBwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9ibGFuaygpKSArIAogICAgICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwLCBsaW5ldHlwZSA9ICJkYXNoZWQiLCBjb2wgPSAiZ3JheSIpICsKICAgICAgZmFjZXRfd3JhcCh+Y2hyLCBzdHJpcC5wb3NpdGlvbiA9ICJib3R0b20iLCBzY2FsZXMgPSJmcmVlX3giLCBucm93ID0gMSl9CgpwMSA8LSBtYWtlQmFyVHVtb3J2c2NmRE5BKCJuZXVyb2JsYXN0b21hIikKcDIgPC0gbWFrZUJhclR1bW9ydnNjZkROQSgibmVwaHJvYmxhc3RvbWEiKQpwMyA8LSBtYWtlQmFyVHVtb3J2c2NmRE5BKCJvc3Rlb3NhcmNvbWEiKQpwNCA8LSBtYWtlQmFyVHVtb3J2c2NmRE5BKCJyaGFiZG9teW9zYXJjb21hIikKcDUgPC0gbWFrZUJhclR1bW9ydnNjZkROQSgiRXdpbmcgc2FyY29tYSIpCmBgYAoKCmBgYHtyLCBmaWcud2lkdGg9IDgsIGZpZy5oZWlnaHQ9IDE2fQpnZ2FycmFuZ2UocDEsIHAyLCBwNCwgcDUsIG5jb2wgPSAxLCBjb21tb24ubGVnZW5kID0gVFJVRSkKCmdnc2F2ZSgiLi9wbG90cy9jb21wYXJhdGl2ZXBsb3QucG5nIiwgcGxvdCA9IGdncGxvdDI6Omxhc3RfcGxvdCgpLCBkcGkgPSAzMDAsIHdpZHRoID0gOCwgaGVpZ2h0ID0gMTIpCmdnc2F2ZSgiLi9wbG90cy9jb21wYXJhdGl2ZXBsb3Quc3ZnIiwgcGxvdCA9IGdncGxvdDI6Omxhc3RfcGxvdCgpLCBkcGkgPSAzMDAsIHdpZHRoID0gOCwgaGVpZ2h0ID0gMTIpCmdnc2F2ZSgiLi9wbG90cy9jb21wYXJhdGl2ZXBsb3QucGRmIiwgcGxvdCA9IGdncGxvdDI6Omxhc3RfcGxvdCgpLCBkcGkgPSAzMDAsIHdpZHRoID0gOCwgaGVpZ2h0ID0gMTIpCmBgYAoKIyBTZXF1ZW5jaW5nIHF1YWxpdHkgY29udHJvbCBtZXRyaWNzCiMjIE1hcHBlZCByZWFkcwpgYGB7cn0KbWFwcGVkX3JlYWRzIDwtIHJlYWRfdHN2KCIuL2RhdGEvbG9ncy9tdWx0aXFjX2RhdGEvbXVsdGlxY19zYW10b29sc19zdGF0cy50eHQiKQptYXBwZWRfcmVhZHMkU2FtcGxlIDwtIGdzdWIoIl8uKiIsICIiLCBtYXBwZWRfcmVhZHMkU2FtcGxlKQptYXBwZWRfcmVhZHMgPC0gaW5uZXJfam9pbihtYXBwZWRfcmVhZHMsIHNhbXBsZV9hbm5vdGF0aW9uX2xvbmcsIGJ5ID0gYygiU2FtcGxlIiA9ICJTYW1wbGVJRCIpKQoKCmdncGxvdChtYXBwZWRfcmVhZHMsIGFlcyh5ID0gYmlvbWF0ZXJpYWwsIHggPSAgcmVhZHNfbWFwcGVkX3BlcmNlbnQsIGZpbGwgPSBiaW9tYXRlcmlhbCApKSArIAogICBnZW9tX2RlbnNpdHlfcmlkZ2VzMihzY2FsZSA9IDAuNSwgYWxwaGEgPSAwLjUsIAogICAgICAgICAgICAgICAgICAgICAgICBqaXR0ZXJlZF9wb2ludHMgPSBUUlVFLCBwb3NpdGlvbiA9ICJyYWluY2xvdWQiLAogICAgICAgICAgICAgICAgICAgICAgICBhZXMocG9pbnRfY29sb3IgPSBiaW9tYXRlcmlhbCwgcG9pbnRfZmlsbCA9IGJpb21hdGVyaWFsKSkgKwogICBnZW9tX2JveHBsb3QoYWxwaGEgPSAwLjUsIHdpZHRoID0gMC4xKSArIHRoZW1lX2J3KCkgKyAKICAgbGltcyh4ID0gYygwLDEwMCkpICsKICAgbGFicyh0aXRsZSA9ICJBbGlnbm1lbnQgcGVyY2VudGFnZSBhY3Jvc3MgYWxsIHNhbXBsZXMiLCB4ID0gInJlYWRzIG1hcHBlZCB3aXRoIGJ3YSBtZW0gKCUpIikKCm1hcHBlZF9yZWFkcyAlPiUgZmlsdGVyKHJlYWRzX21hcHBlZF9wZXJjZW50IDwgMjQpICU+JSBzZWxlY3QoU2FtcGxlLCByZWFkc19tYXBwZWRfcGVyY2VudCkKCmdnc2F2ZSgiLi9wbG90cy9tYXBwZWRfcmVhZHMucG5nIiwgcGxvdCA9IGdncGxvdDI6Omxhc3RfcGxvdCgpLCBkcGkgPSAzMDAsIHdpZHRoID0gNiwgaGVpZ2h0ID0gNCkKZ2dzYXZlKCIuL3Bsb3RzL21hcHBlZF9yZWFkcy5zdmciLCBwbG90ID0gZ2dwbG90Mjo6bGFzdF9wbG90KCksIGRwaSA9IDMwMCwgd2lkdGggPSA2LCBoZWlnaHQgPSA0KQpnZ3NhdmUoIi4vcGxvdHMvbWFwcGVkX3JlYWRzLnBkZiIsIHBsb3QgPSBnZ3Bsb3QyOjpsYXN0X3Bsb3QoKSwgZHBpID0gMzAwLCB3aWR0aCA9IDYsIGhlaWdodCA9IDQpCmBgYAoKCiMjIER1cGxpY2F0ZSBwZXJjZW50YWdlCmBgYHtyfQpkdXBsaWNhdGVkX3JlYWRzIDwtIHJlYWRfdHN2KCIuL2RhdGEvbG9ncy9tdWx0aXFjX2RhdGEvbXVsdGlxY19waWNhcmRfZHVwcy50eHQiKQpkdXBsaWNhdGVkX3JlYWRzJFNhbXBsZSA8LSBnc3ViKCJfLioiLCAiIiwgZHVwbGljYXRlZF9yZWFkcyRTYW1wbGUpCmR1cGxpY2F0ZWRfcmVhZHMgPC0gaW5uZXJfam9pbihkdXBsaWNhdGVkX3JlYWRzLCBzYW1wbGVfYW5ub3RhdGlvbl9sb25nLCBieSA9IGMoIlNhbXBsZSIgPSAiU2FtcGxlSUQiKSkKZHVwbGljYXRlZF9yZWFkcyRkdXBsaWNhdGVfcGVyY2VudGFnZSA8LSBkdXBsaWNhdGVkX3JlYWRzJFVOUEFJUkVEX1JFQURfRFVQTElDQVRFUy9kdXBsaWNhdGVkX3JlYWRzJFVOUEFJUkVEX1JFQURTX0VYQU1JTkVEKjEwMAoKZ2dwbG90KGR1cGxpY2F0ZWRfcmVhZHMsIGFlcyh5ID0gYmlvbWF0ZXJpYWwsIHggPSAgVU5QQUlSRURfUkVBRF9EVVBMSUNBVEVTL1VOUEFJUkVEX1JFQURTX0VYQU1JTkVEKjEwMCwgZmlsbCA9IGJpb21hdGVyaWFsICkpICsgCiAgIGdlb21fZGVuc2l0eV9yaWRnZXMyKHNjYWxlID0gMC41LCBhbHBoYSA9IDAuNSwgCiAgICAgICAgICAgICAgICAgICAgICAgIGppdHRlcmVkX3BvaW50cyA9IFRSVUUsIHBvc2l0aW9uID0gInJhaW5jbG91ZCIsCiAgICAgICAgICAgICAgICAgICAgICAgIGFlcyhwb2ludF9jb2xvciA9IGJpb21hdGVyaWFsLCBwb2ludF9maWxsID0gYmlvbWF0ZXJpYWwpKSArCiAgIGdlb21fYm94cGxvdChhbHBoYSA9IDAuNSwgd2lkdGggPSAwLjEpICsgdGhlbWVfYncoKSArIAogICBsaW1zKHggPSBjKDAsMTAwKSkgKwogICBsYWJzKHRpdGxlID0gImR1cGxpY2F0ZSBwZXJjZW50YWdlIGFjcm9zcyBhbGwgc2FtcGxlcyIsIHggPSAiZHVwbGljYXRlIHJlYWRzIHdpdGggUGljYXJkICglKSIpIAoKZ2dzYXZlKCIuL3Bsb3RzL2R1cGxpY2F0ZV9wZXJjLnBuZyIsIHBsb3QgPSBnZ3Bsb3QyOjpsYXN0X3Bsb3QoKSwgZHBpID0gMzAwLCB3aWR0aCA9IDYsIGhlaWdodCA9IDQpCmdnc2F2ZSgiLi9wbG90cy9kdXBsaWNhdGVfcGVyYy5zdmciLCBwbG90ID0gZ2dwbG90Mjo6bGFzdF9wbG90KCksIGRwaSA9IDMwMCwgd2lkdGggPSA2LCBoZWlnaHQgPSA0KQpnZ3NhdmUoIi4vcGxvdHMvZHVwbGljYXRlX3BlcmMucGRmIiwgcGxvdCA9IGdncGxvdDI6Omxhc3RfcGxvdCgpLCBkcGkgPSAzMDAsIHdpZHRoID0gNiwgaGVpZ2h0ID0gNCkKCmdncGxvdChtYXBwZWRfcmVhZHMsIGFlcyh5ID0gYmlvbWF0ZXJpYWwsIHggPSAgcmVhZHNfbWFwcGVkLCBmaWxsID0gYmlvbWF0ZXJpYWwgKSkgKyAKICAgZ2VvbV9kZW5zaXR5X3JpZGdlczIoc2NhbGUgPSAwLjUsIGFscGhhID0gMC41LCAKICAgICAgICAgICAgICAgICAgICAgICAgaml0dGVyZWRfcG9pbnRzID0gVFJVRSwgcG9zaXRpb24gPSAicmFpbmNsb3VkIiwKICAgICAgICAgICAgICAgICAgICAgICAgYWVzKHBvaW50X2NvbG9yID0gYmlvbWF0ZXJpYWwsIHBvaW50X2ZpbGwgPSBiaW9tYXRlcmlhbCkpICsKICAgZ2VvbV9ib3hwbG90KGFscGhhID0gMC41LCB3aWR0aCA9IDAuMSkgKyB0aGVtZV9idygpICsgCiAgICNsaW1zKHggPSBjKDAsMTAwKSkgKwogICBsYWJzKHRpdGxlID0gImFic29sdXRlIG51bWJlciBvZiBtYXBwZWQgcmVhZHMgYWZ0ZXIgZGVkdXBsaWNhdGlvbiIsIHggPSAibnVtYmVyIG9mIHJlbWFpbmluZyByZWFkcyIpIApgYGAKCiMgQ05BcyBpbiB0dW1vciB0aXNzdWUKCmBgYHtyfQpnZ3Bsb3QoY2ZETkF2c1Rpc3N1ZSwgYWVzKHggPSBUdW1vckFiYnJldiwgeSA9IGNwYV90dW1vckROQSwgY29sID0gdHVtb3JETkFfQ05Bc19jb25zZW5zdXMsIGxhYmVsID0gUGF0aWVudElEKSkrIHRoZW1lX2J3KCkgICsKICAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSxoanVzdD0xKSkgICsgZ2VvbV9ib3hwbG90KGFscGhhID0gMC40LCBhZXMoY29sID0gTlVMTCkpICsgZ2VvbV9iZWVzd2FybShhbHBoYSA9IDAuNykgICsgZmFjZXRfd3JhcCh+VHVtb3JHcm91cCwgc2NhbGVzID0gImZyZWVfeCIpICsgbGFicyh5ID0gIkNQQW0gdHVtb3JETkEiKQoKZ2dzYXZlKCIuL3Bsb3RzL0NQQV90dW1vci5wbmciLCBwbG90ID0gZ2dwbG90Mjo6bGFzdF9wbG90KCksIGRwaSA9IDMwMCwgd2lkdGggPSAxMCwgaGVpZ2h0ID0gNikKZ2dzYXZlKCIuL3Bsb3RzL0NQQV90dW1vci5zdmciLCBwbG90ID0gZ2dwbG90Mjo6bGFzdF9wbG90KCksIGRwaSA9IDMwMCwgd2lkdGggPSAxMCwgaGVpZ2h0ID0gNikKZ2dzYXZlKCIuL3Bsb3RzL0NQQV90dW1vci5wZGYiLCBwbG90ID0gZ2dwbG90Mjo6bGFzdF9wbG90KCksIGRwaSA9IDMwMCwgd2lkdGggPSAxMCwgaGVpZ2h0ID0gNikKCmdncGxvdChjZkROQXZzVGlzc3VlICU+JSBmaWx0ZXIodHVtb3JETkFfQ05Bc19yYXRlcjEgIT0gIk5BIiksIGFlcyh4ID0gY3BhX3R1bW9yRE5BLCBmaWxsID0gdHVtb3JETkFfQ05Bc19jb25zZW5zdXMpKSArIGdlb21fYm94cGxvdChhbHBoYSA9IDAuNSkgKyBmYWNldF93cmFwKH4gdHVtb3JETkFfYXNzYXkgKyB0dW1vckROQV9iaW9tYXRlcmlhbCkgKyB0aGVtZV9idygpCgpgYGAKCi0gVGhlIG51bWJlciBvZiB0dW1vciBzYW1wbGVzIHdpdGggQ05BczogIGByIGNmRE5BdnNUaXNzdWUgJT4lIGZpbHRlcih0dW1vckROQV9DTkFzX2NvbnNlbnN1cyA9PSAiVFJVRSIpICU+JSBwdWxsKHR1bW9yRE5BX0NOQXNfY29uc2Vuc3VzKSAlPiUgbGVuZ3RoKCkgYAotIFRoZSBudW1iZXIgb2YgdHVtb3Igc2FtcGxlcyB3aXRoIG5vIENOQXM6ICBgciBjZkROQXZzVGlzc3VlICU+JSBmaWx0ZXIodHVtb3JETkFfQ05Bc19jb25zZW5zdXMgPT0gIkZBTFNFIikgJT4lIHB1bGwodHVtb3JETkFfQ05Bc19jb25zZW5zdXMpICU+JSBsZW5ndGgoKSBgCi0gVGhlIG51bWJlciBvZiBjZkROQSBzYW1wbGVzIHdpdGggQ05BczogIGByIGNmRE5BdnNUaXNzdWUgJT4lIGZpbHRlcihDTkFfY2ZETkEgPT0gIkNOQSIpICU+JSBwdWxsKENOQV9jZkROQSkgJT4lIGxlbmd0aCgpIGAKLSBUaGUgbnVtYmVyIG9mIGNmRE5BIHNhbXBsZXMgYmVpbmcgZmxhdDogIGByIGNmRE5BdnNUaXNzdWUgJT4lIGZpbHRlcihDTkFfY2ZETkEgPT0gImZsYXQiKSAlPiUgcHVsbChDTkFfY2ZETkEpICU+JSBsZW5ndGgoKSBgCi0gVGhlIG1lZGlhbiBDUEFtIGluIHR1bW9yczogYHIgbWVkaWFuKGNmRE5BdnNUaXNzdWUkY3BhX3R1bW9yRE5BKWAgYW5kIFExL1EzIGByIHF1YW50aWxlKGNmRE5BdnNUaXNzdWUkY3BhX3R1bW9yRE5BKWAKLSBUaGUgbWVkaWFuIENQQW0gaW4gY2ZETkE6IGByIG1lZGlhbihjZkROQXZzVGlzc3VlJGNwYV9jZkROQSlgIGFuZCBRMS9RMyBgciBxdWFudGlsZShjZkROQXZzVGlzc3VlJGNwYV9jZkROQSlgCgojIENvbXBhcmlzb24gb2YgY2ZETkEgdnMgdGlzc3VlCgojIyBDcm9zc3RhYmxlIG9mIGNmRE5BIGFuZCB0dW1vciBDTkFzIHsudGFic2V0fQojIyMgQWxsIHNhbXBsZXMKYGBge3J9CmNmRE5BdnNUaXNzdWUkQ05BX2NmRE5BX2Jvb2wgPC0gaWZlbHNlKGNmRE5BdnNUaXNzdWUkQ05BX2NmRE5BID09ICJDTkEiLCBUUlVFLCBGQUxTRSkKY2ZETkF2c1Rpc3N1ZSR0dW1vckROQV9DTkFzX2NvbnNlbnN1cyA8LSBhcy5sb2dpY2FsKGNmRE5BdnNUaXNzdWUkdHVtb3JETkFfQ05Bc19jb25zZW5zdXMpCnNqdC54dGFiKGNmRE5BdnNUaXNzdWUkdHVtb3JETkFfQ05Bc19jb25zZW5zdXMgLCBjZkROQXZzVGlzc3VlJENOQV9jZkROQV9ib29sLCB2YXIubGFiZWxzPWMoInR1bW9yIiwgImNmRE5BIiksIHZhbHVlLmxhYmVscyA9IGxpc3QoYygibmV1dHJhbCIsICJDTkEiKSwgYygibmV1dHJhbCIsICJDTkEiKSksIHRpdGxlID0gImNyb3NzdGFibGUgZm9yIGFsbCBzYW1wbGVzIikKYGBgCgojIyMgY2ZETkEvSE1XIHJhdGlvIDwgMQpgYGB7cn0Kc2p0Lnh0YWIoY2ZETkF2c1Rpc3N1ZSAlPiUgZmlsdGVyKGNmRE5BX0hNV19yYXRpbyA8IDEpICU+JSBwdWxsKHR1bW9yRE5BX0NOQXNfY29uc2Vuc3VzKSAsIGNmRE5BdnNUaXNzdWUgJT4lIGZpbHRlcihjZkROQV9ITVdfcmF0aW8gPCAxKSAlPiUgcHVsbChDTkFfY2ZETkFfYm9vbCksIHZhci5sYWJlbHM9YygidHVtb3IiLCAiY2ZETkEiKSwgdmFsdWUubGFiZWxzID0gbGlzdChjKCJuZXV0cmFsIiwgIkNOQSIpLCBjKCJuZXV0cmFsIiwgIkNOQSIpKSwgdGl0bGUgPSAiY3Jvc3N0YWJsZSBmb3Igc2FtcGxlcyB3aXRoIGEgY2ZETkEvSE1XIHJhdGlvIDwgMSIpCmBgYAoKIyMjIGNmRE5BL0hNVyByYXRpbyAxLTUKYGBge3J9CnNqdC54dGFiKGNmRE5BdnNUaXNzdWUgJT4lIGZpbHRlcihjZkROQV9ITVdfcmF0aW8gPj0gMSAmIGNmRE5BX0hNV19yYXRpbyA8IDUpICU+JSBwdWxsKHR1bW9yRE5BX0NOQXNfY29uc2Vuc3VzKSAsIGNmRE5BdnNUaXNzdWUgJT4lIGZpbHRlcihjZkROQV9ITVdfcmF0aW8gPj0gMSAmIGNmRE5BX0hNV19yYXRpbyA8IDUpICU+JSBwdWxsKENOQV9jZkROQV9ib29sKSwgdmFyLmxhYmVscz1jKCJ0dW1vciIsICJjZkROQSIpLCB2YWx1ZS5sYWJlbHMgPSBsaXN0KGMoIm5ldXRyYWwiLCAiQ05BIiksIGMoIm5ldXRyYWwiLCAiQ05BIikpLCB0aXRsZSA9ICJjcm9zc3RhYmxlIGZvciBzYW1wbGVzIHdpdGggYSBjZkROQS9ITVcgcmF0aW8gWzEsNV0iKQpgYGAKCiMjIyBjZkROQS9ITVcgcmF0aW8gPiA1CmBgYHtyfQpzanQueHRhYihjZkROQXZzVGlzc3VlICU+JSBmaWx0ZXIoY2ZETkFfSE1XX3JhdGlvID4gNSkgJT4lIHB1bGwodHVtb3JETkFfQ05Bc19jb25zZW5zdXMpICwgY2ZETkF2c1Rpc3N1ZSAlPiUgZmlsdGVyKGNmRE5BX0hNV19yYXRpbyA+PSA1ICkgJT4lIHB1bGwoQ05BX2NmRE5BX2Jvb2wpLCB2YXIubGFiZWxzPWMoInR1bW9yIiwgImNmRE5BIiksIHZhbHVlLmxhYmVscyA9IGxpc3QoYygibmV1dHJhbCIsICJDTkEiKSwgYygibmV1dHJhbCIsICJDTkEiKSksIHRpdGxlID0gImNyb3NzdGFibGUgZm9yIHNhbXBsZXMgd2l0aCBhIGNmRE5BL0hNVyByYXRpbyA+IDUgIikKYGBgCgoKYGBge3J9CmNmRE5BdnNUaXNzdWUkQ05BX2NmRE5BX2Jvb2wgPC0gaWZlbHNlKGNmRE5BdnNUaXNzdWUkQ05BX2NmRE5BID09ICJDTkEiLCBUUlVFLCBGQUxTRSkKY2ZETkF2c1Rpc3N1ZSR0dW1vckROQV9DTkFzX2NvbnNlbnN1cyA8LSBhcy5sb2dpY2FsKGNmRE5BdnNUaXNzdWUkdHVtb3JETkFfQ05Bc19jb25zZW5zdXMpCnNqdC54dGFiKGNmRE5BdnNUaXNzdWUkdHVtb3JETkFfQ05Bc19jb25zZW5zdXMgLCBjZkROQXZzVGlzc3VlJENOQV9jZkROQV9ib29sLCB2YXIubGFiZWxzPWMoInR1bW9yIiwgImNmRE5BIiksIHZhbHVlLmxhYmVscyA9IGxpc3QoYygibmV1dHJhbCIsICJDTkEiKSwgYygibmV1dHJhbCIsICJDTkEiKSkpCmBgYAoKIyMgQ29ycmVsYXRpb24gb2YgQ1BBbSBhbmQgQ1BBCgpXaGVyZSBwb3NzaWJsZSAoc2hhbGxvdyBXR1Mgc2FtcGxlcywgbiA9IDgyKSwgdGhlIGNvcnJlbGF0aW9uIGJldHdlZW4gdGhlIENQQSBhbmQgQ1BBbSB3YXMgY2FsY3VsYXRlZCBhbmQgeWllbGRlZCBhIFBlYXJzb24gUiBvZiAwLjc0IGFuZCBhIHNwZWFybWFuIHJobyBvZiAwLjg2LiBUaGUgQ1BBbSB0aHJlc2hvbGQgb2YgY29weSBudW1iZXIgbmV1dHJhbCAo4oCcbm9ybWFs4oCdIG9yIOKAnGZsYXTigJ0pIGF0IHRoZSAxJSBmYWxzZSBkaXNjb3ZlcnkgbGV2ZWwgaW4gY2ZETkEgd2FzIGNhbGN1bGF0ZWQgb24gdGhlIGNvaG9ydCBvZiBoZWFsdGh5IGNvbnRyb2xzIChpbmRpdmlkdWFscyBhYm92ZSAxOCB5ZWFycyBvbGQgd2l0aCBubyBjYW5jZXIgZGlhZ25vc2lzIGluIHRoZWlyIHBhc3QgbWVkaWNhbCBoaXN0b3J5KSBmcm9tIFJhbWFuIGV0IGFsLiBhbmQgd2FzIGZvdW5kIHRvIGJlIDAuMzU0LiBXaXRoIHRoaXMgdGhyZXNob2xkLCB0aGVyZSBhcmUgNC84MiBjZkROQSBzYW1wbGVzIHRoYXQgd2VyZSBsYWJlbGVkIGRpc2NvcmRhbnQsIGkuZS4sIGNvcHkgbnVtYmVyIG5ldXRyYWwgd2l0aCBDUEEgYW5kIGNvcHkgbnVtYmVyIGFiZXJyYXRpb25zIHdpdGggQ1BBbS4gVXBvbiBtYW51YWwgaW5zcGVjdGlvbiwgMyBvdXQgb2YgdGhlc2UgNCBzYW1wbGVzIGNvbnRhaW4gdmlzaWJsZSBDTkFzLCB3aGlsZSAxIG91dCBvZiA0IHNhbXBsZXMgaXMgY29weSBudW1iZXIgbmV1dHJhbC4KCmBgYHtyfQpDUEFfZGYgPC0gcmVhZF9jc3YoIi4vZGF0YS9zV0dTX3Rpc3N1ZS9DUEFfYWxsLmNzdiIpCgpzcGVhcm1hbl9jb3IgPC0gY29yKENQQV9kZiRDUEEsIENQQV9kZiRDUEFtLCBtZXRob2QgPSAic3BlYXJtYW4iKQoKZ2dwbG90KENQQV9kZiwgYWVzKHggPSBDUEEsIHkgPSBDUEFtKSkgKyBnZW9tX3BvaW50KCkgKyBnZW9tX3Ntb290aChtZXRob2QgPSAnbG0nKSArIHRoZW1lX2J3KCkgKyBsYWJzKHRpdGxlID0gcGFzdGUwKCJDb3JyZWxhdGlvbiBiZXR3ZWVuIG1vZGlmaWVkIENQQSAoQ1BBbSkgYW5kIG9yaWdpbmFsIENQQSIpLCBzdWJ0aXRsZSA9IHBhc3RlMCgiU3BlYXJtYW4gcmhvID0gIiwgcm91bmQoc3BlYXJtYW5fY29yLCA0KSkpICsgYW5ub3RhdGUoInJlY3QiLHltaW4gPSAwLCB5bWF4ID0gRkRSX0NQQW0sIHhtaW4gPSAtSW5mLCB4bWF4ID0gSW5mLCBhbHBoYT0wLjMsIGZpbGw9ImdyZXkiKSArIHNjYWxlX3NoYXBlX21hbnVhbCh2YWx1ZXM9YygxLDEsMSwxLDEpKSArIGFubm90YXRlKCJyZWN0Iix4bWluID0gMCwgeG1heCA9IEZEUl9DUEEsIHltaW4gPSAtSW5mLCB5bWF4ID0gSW5mLCBhbHBoYT0wLjMsIGZpbGw9ImdyZXkiKSArIHNjYWxlX3NoYXBlX21hbnVhbCh2YWx1ZXM9YygxLDEsMSwxLDEpKQpgYGAKClRoZSBzYW1wbGVzIHRoYXQgd2VyZSBkaXNjb3JkYW50IGJldHdlZW4gQ1BBICgxJSBGRFIgPSBgciBGRFJfQ1BBYCkgYW5kIENQQW0gKDElIEZEUiA9IGByIEZEUl9DUEFtYCkgYXJlOgoKYGBge3J9CkNQQV9kZiAlPiUgZmlsdGVyKENQQSA+IEZEUl9DUEEgJiBDUEFtIDwgRkRSX0NQQW0gfCBDUEEgPCBGRFJfQ1BBICYgQ1BBbSA+IEZEUl9DUEFtICkKYGBgCgojIyBEaXN0cmlidXRpb24gb2YgQ1BBIGluIHRpc3N1ZSBETkEgYW5kIGNmRE5BCmBgYHtyfQpjb25mbGljdF9wcmVmZXIoIm1lbHQiLCAiZGF0YS50YWJsZSIpCkNQQW1fcmlkZ2UgPC0gZ2dwbG90KAogICBjZkROQXZzVGlzc3VlICU+JSBzZWxlY3QoY3BhX3R1bW9yRE5BLCBjcGFfY2ZETkEsIGNwYV90eXBlKQogICAlPiUgZmlsdGVyKGNwYV90eXBlID09ICJDUEFtIikgJT4lIG1lbHQoKSwgCiAgIGFlcyh5ID0gdmFyaWFibGUsIHggPSB2YWx1ZSwgZmlsbCA9IHZhcmlhYmxlKSkgKwogICBnZW9tX2RlbnNpdHlfcmlkZ2VzMihzY2FsZSA9IDAuOCwgcGFuZWxfc2NhbGluZyA9IEZBTFNFLAogICAgICAgICAgICAgICAgICAgICAgICBwb2ludF9hbHBoYSA9IDAuNSwgYWxwaGEgPSAuMiwgCiAgICAgICAgICAgICAgICAgICAgICAgIGFlcyhwb2ludF9jb2xvciA9IHZhcmlhYmxlLCBwb2ludF9maWxsID0gdmFyaWFibGUpLAogICAgICAgICAgICAgICAgICAgICAgICBqaXR0ZXJlZF9wb2ludHMgPSBUUlVFLCBwb3NpdGlvbiA9ICJyYWluY2xvdWQiKSArCiAgIHRoZW1lX2J3KCkgKyAKICAgbGFicyhmaWxsID0gInR1bW9yIiwgcG9pbnRfZmlsbCA9ICJ0dW1vciIsIHBvaW50X2NvbG9yID0gInR1bW9yIiwgeCA9ICJDUEFtIiwgeSA9ICJ0dW1vciIsIHRpdGxlID0gIm1vZGlmaWVkIENQQSIpICArIAogICBnZW9tX2JveHBsb3QoYWxwaGEgPSAwLjQsIHdpZHRoID0gMC4xKQoKQ1BBbV9yaWRnZQoKZ2dzYXZlKCIuL3Bsb3RzL0NQQW1fcmlkZ2VwbG90LnBuZyIsIHBsb3QgPSBnZ3Bsb3QyOjpsYXN0X3Bsb3QoKSwgZHBpID0gMzAwLCB3aWR0aCA9IDgsIGhlaWdodCA9IDYpCmdnc2F2ZSgiLi9wbG90cy9DUEFtX3JpZGdlcGxvdC5zdmciLCBwbG90ID0gZ2dwbG90Mjo6bGFzdF9wbG90KCksIGRwaSA9IDMwMCwgd2lkdGggPSA4LCBoZWlnaHQgPSA2KQpnZ3NhdmUoIi4vcGxvdHMvQ1BBbV9yaWRnZXBsb3QucGRmIiwgcGxvdCA9IGdncGxvdDI6Omxhc3RfcGxvdCgpLCBkcGkgPSAzMDAsIHdpZHRoID0gOCwgaGVpZ2h0ID0gNikKYGBgCgojIyBjZkROQS9ITVcgcmF0aW8gZGlzdHJpYnV0aW9uCmBgYHtyfQpnZ3Bsb3QoY2ZETkF2c1Rpc3N1ZSwgYWVzKHggPSBhcy5udW1lcmljKGNmRE5BX0hNV19yYXRpbykpKSArIAogICBnZW9tX2RlbnNpdHkoYWxwaGEgPSAwLjUsIGZpbGwgPSAiZ3JheSIsIGNvbCA9ICJibGFjayIpICsgdGhlbWVfYncoKSArIHNjYWxlX3hfbG9nMTAoKStsYWJzKHggPSAiY2ZETkEvSE1XIHJhdGlvIikgCgoKZ2dwbG90KGNmRE5BdnNUaXNzdWUsIGFlcyhjb2wgPSBUdW1vckdyb3VwLCB5ID0gYXMubnVtZXJpYyhjcGFfY2ZETkEpLCB4ID0gYXMubnVtZXJpYyhjZkROQV9ITVdfcmF0aW8pKSkgKyAKICAgZ2VvbV9wb2ludChhbHBoYSA9IDAuOCkgKyB0aGVtZV9idygpICsgCiAgIGZhY2V0X3dyYXAofmNwYV90eXBlLCBzY2FsZXMgPSAiZnJlZV95IikgKyBsYWJzKGNvbCA9ICJjZkROQS9ITVcgcmF0aW8iKSAgKyAKICAgc2NhbGVfeF9sb2cxMCgpICsgCiAgIGxhYnMoY29sID0gInR1bW9yIHR5cGUiLCB5ID0gIkNQQW0gY2ZETkEiLCB4ID0gImNmRE5BL0hNVyByYXRpbyIpIAoKZ2dzYXZlKCIuL3Bsb3RzL0NQQW1fY2ZETkF2c1NhbXBsZVEucG5nIiwgcGxvdCA9IGdncGxvdDI6Omxhc3RfcGxvdCgpLCBkcGkgPSAzMDAsIHdpZHRoID0gOCwgaGVpZ2h0ID0gNikKZ2dzYXZlKCIuL3Bsb3RzL0NQQW1fY2ZETkF2c1NhbXBsZVEuc3ZnIiwgcGxvdCA9IGdncGxvdDI6Omxhc3RfcGxvdCgpLCBkcGkgPSAzMDAsIHdpZHRoID0gOCwgaGVpZ2h0ID0gNikKZ2dzYXZlKCIuL3Bsb3RzL0NQQW1fY2ZETkF2c1NhbXBsZVEucGRmIiwgcGxvdCA9IGdncGxvdDI6Omxhc3RfcGxvdCgpLCBkcGkgPSAzMDAsIHdpZHRoID0gOCwgaGVpZ2h0ID0gNikKYGBgCgojIyBDUEEgY2ZETkEgdnMgUGVhcnNvbiBSIH4gY2ZETkEvSE1XIHJhdGlvCmBgYHtyfQpCZWZvcmVBZnRlciA8LSBjZkROQXZzVGlzc3VlCgpCZWZvcmVBZnRlciRjZkROQV9ITVdfcmF0aW8gPC0gYXMuY2hhcmFjdGVyKEJlZm9yZUFmdGVyJGNmRE5BX0hNV19yYXRpbyApCkJlZm9yZUFmdGVyJGNvbExhYmVsIDwtIGlmZWxzZShjZkROQXZzVGlzc3VlJGNwYV90dW1vckROQSA+IEZEUl9DUEFtICYgY2ZETkF2c1Rpc3N1ZSRjcGFfY2ZETkEgPCBGRFJfQ1BBbSwgImxhYmVsIiwgICIiKQpCZWZvcmVBZnRlcl9tZWx0IDwtIEJlZm9yZUFmdGVyICU+JSBzZWxlY3QoVHVtb3JUeXBlLCBjb2xMYWJlbCwgUGF0aWVudElELCBjcGFfdHVtb3JETkEsIGNwYV9jZkROQSwgY3BhX3R5cGUsIFR1bW9yR3JvdXAsIHR1bW9yRE5BX2Fzc2F5X2RldGFpbCwgY2ZETkFfSE1XX3JhdGlvKSAlPiUgZmlsdGVyKGNwYV90eXBlID09ICJDUEFtIikgJT4lIG1lbHQoKQpCZWZvcmVBZnRlcl9tZWx0JGNmRE5BX0hNV19yYXRpbyA8LSBpZmVsc2UoQmVmb3JlQWZ0ZXJfbWVsdCR2YXJpYWJsZSA9PSAiY3BhX3R1bW9yRE5BIiwgMCwgYXMubnVtZXJpYyhCZWZvcmVBZnRlcl9tZWx0JGNmRE5BX0hNV19yYXRpbykpCgpnZ3Bsb3QoQmVmb3JlQWZ0ZXJfbWVsdCwgCiAgICAgICBhZXMoY29sID0gY29sTGFiZWwsIHggPSB2YXJpYWJsZSwgeSA9IHZhbHVlLCBncm91cCA9IFBhdGllbnRJRCwgYWxwaGEgPSBjb2xMYWJlbCkpICsgCiAgIGdlb21fbGluZShwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMC41KSkgKyAKICAgZ2VvbV9wb2ludChkYXRhID0gQmVmb3JlQWZ0ZXJfbWVsdCwgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDAuNSksIGFlcyhzaXplID0gY2ZETkFfSE1XX3JhdGlvKSkgKyAKICAgc2NhbGVfeV9sb2cxMCgpICsgdGhlbWVfYncoKSArIAogICBmYWNldF93cmFwKH5UdW1vckdyb3VwLCBuY29sID0gMikgKyAKICAgbGFicyhzaXplID0gImNmRE5BL0hNVyByYXRpbyIsIHggPSAiYmlvbWF0ZXJpYWwiLCB5ID0gIkNQQW0iKSArCiAgIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9YygiZ3JheSIsICJuYXZ5Ymx1ZSIpKSArIAogICBzY2FsZV9hbHBoYV9kaXNjcmV0ZShyYW5nZSA9IGMoMC41LCAwLjkpKSArIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJyaWdodCIpCgpnZ3NhdmUoIi4vcGxvdHMvYmVmb3JlQWZ0ZXIucG5nIiwgcGxvdCA9IGdncGxvdDI6Omxhc3RfcGxvdCgpLCBkcGkgPSAzMDAsIHdpZHRoID0gOCwgaGVpZ2h0ID0gOSkKZ2dzYXZlKCIuL3Bsb3RzL2JlZm9yZUFmdGVyLnN2ZyIsIHBsb3QgPSBnZ3Bsb3QyOjpsYXN0X3Bsb3QoKSwgZHBpID0gMzAwLCB3aWR0aCA9IDgsIGhlaWdodCA9IDkpCmdnc2F2ZSgiLi9wbG90cy9iZWZvcmVBZnRlci5wZGYiLCBwbG90ID0gZ2dwbG90Mjo6bGFzdF9wbG90KCksIGRwaSA9IDMwMCwgd2lkdGggPSA4LCBoZWlnaHQgPSA5KQoKY2ZETkF2c1Rpc3N1ZSRsYWJlbGZpZyA8LSBpZmVsc2UoY2ZETkF2c1Rpc3N1ZSRQYXRpZW50SUQgPT0gInBhdGllbnRfMDc5IiwgInBhdGllbnRfMDc5IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKGNmRE5BdnNUaXNzdWUkUGF0aWVudElEID09ICJwYXRpZW50XzIxMiIsICJwYXRpZW50XzIxMiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoY2ZETkF2c1Rpc3N1ZSRQYXRpZW50SUQgPT0gInBhdGllbnRfMDc3IiwgInBhdGllbnRfMDc3IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoY2ZETkF2c1Rpc3N1ZSRQYXRpZW50SUQgPT0gInBhdGllbnRfMTk2IiwgInBhdGllbnRfMTk2IiwgIiIpKSkpCnBfQ1BBdnNSIDwtIGdncGxvdChjZkROQXZzVGlzc3VlLCBhZXMoeCA9ICBhcy5udW1lcmljKGNwYV9jZkROQSksIHkgPSBwZWFyc29uUiwgc2l6ZSA9IGFzLm51bWVyaWMoY2ZETkFfSE1XX3JhdGlvKSwgc2hhcGUgPSB0dW1vckROQV9hc3NheV9kZXRhaWwsIGNvbCA9IHR1bW9yRE5BX2Fzc2F5X2RldGFpbCwgbGFiZWwgPSBsYWJlbGZpZykpICsgCiAgIGdlb21fcG9pbnQoYWxwaGEgPSAxKSArIHRoZW1lX2J3KCkgKyAKICAgbGFicyhzaXplID0gImNmRE5BL0hNVyByYXRpbyIsIHggPSAiQ1BBbSBjZkROQSIsIHkgPSAiUGVhcnNvbiBSIiwgY29sID0gInRpc3N1ZSBETkEgcGxhdGZvcm0iLCBzaGFwZSA9ICJ0aXNzdWUgRE5BIHBsYXRmb3JtIikgKyB0aGVtZShsZWdlbmQucG9zaXRpb249ImxlZnQiKSsKICAgZ2VvbV92bGluZShkYXRhPWNmRE5BdnNUaXNzdWUgJT4lIGZpbHRlcihjcGFfdHlwZSA9PSAiQ1BBbSIpLCBhZXMoeGludGVyY2VwdCA9IEZEUl9DUEFtKSwgbGluZXR5cGUgPSAiZGFzaGVkIikrCiAgIGFubm90YXRlKCJyZWN0Iix4bWluID0gMCwgeG1heCA9IEZEUl9DUEFtLCB5bWluID0gLUluZiwgeW1heCA9IEluZiwgYWxwaGE9MC4zLCBmaWxsPSJncmV5IikgKyBzY2FsZV9zaGFwZV9tYW51YWwodmFsdWVzPWMoMSwxLDEsMSwxKSkgKwogICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gYygiI0Y4NzY2RCIsICIjN0NBRTAwIiwgIiM3Q0FFMDAiLCAiIzAwQkZDNCIsICIjQzc3Q0ZGIikpICsgZ2VvbV90ZXh0X3JlcGVsKHNpemUgPSA0LCBzaG93LmxlZ2VuZCA9IEZBTFNFKQoKI3BfQ1BBdnNSCgojZ2dhcnJhbmdlKENQQW1fcmlkZ2UsIHBfQ1BBdnNSLCBsZWdlbmQgPSAiYm90dG9tIikKYGBgCgojIyBUdW1vciB0eXBlcyBpbiBkYXRhc2V0CmBgYHtyfQpjZkROQXZzVGlzc3VlJFR1bW9yVHlwZSA8LSBnc3ViKCJtYWxpZ25hbnQgcmhhYmRvaWQgdHVtb3Igb2YgdGhlIGtpZG5leSIsICJNUlRLIiwgY2ZETkF2c1Rpc3N1ZSRUdW1vclR5cGUpCnAxIDwtIGdncGxvdChjZkROQXZzVGlzc3VlICU+JSBkaXN0aW5jdChQYXRpZW50SUQsIC5rZWVwX2FsbCA9IFRSVUUpLCBhZXMoZmlsbCA9IFNhbXBsZU9yaWdpbiwgeCA9IHJlb3JkZXIoVHVtb3JUeXBlLCBUdW1vclR5cGUsIGZ1bmN0aW9uKHgpIC1sZW5ndGgoeCkpKSkgKyB0aGVtZV9idygpICsKICAgZ2VvbV9iYXIoYWxwaGEgPSAwLjkpICsgbGFicyh4ID0gIiIsIHRpdGxlID0gImFsbCB0dW1vciB0eXBlcyIsIHkgPSAibnVtYmVyIG9mIHVuaXF1ZSBjYXNlcyIsIGZpbGwgPSBOVUxMKSsgCiAgIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsaGp1c3Q9MSkpICArCiAgIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IHFnX3BhbGV0dGUoIlVTb3BlbiIpW2MoNCwxOjMpXSkKCnAyIDwtIGdncGxvdChjZkROQXZzVGlzc3VlLCBhZXMoZmlsbCA9IFNhbXBsZU9yaWdpbiwgeCA9IHJlb3JkZXIodHVtb3JETkFfYXNzYXlfZGV0YWlsLCB0dW1vckROQV9hc3NheV9kZXRhaWwsIGZ1bmN0aW9uKHgpIC1sZW5ndGgoeCkpKSkgKyB0aGVtZV9idygpICsKICAgZ2VvbV9iYXIoYWxwaGEgPSAwLjkpICsgbGFicyh4ID0gIiIsIHRpdGxlID0gInRpc3N1ZSBETkEgcGxhdGZvcm0iLCB5ID0gIm51bWJlciBvZiBzYW1wbGVzIiwgZmlsbCA9IE5VTEwpKyAKICAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSxoanVzdD0xKSkgICsKICAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gcWdfcGFsZXR0ZSgiVVNvcGVuIilbYyg0LDE6MyldKQoKZ2dhcnJhbmdlKHAxLCBwMiwgbGFiZWxzID0gYygiQSIsICJCIiksIGFsaWduID0gYygiaCIpLCB3aWR0aHMgPSBjKDAuNiwgMC40KSwgY29tbW9uLmxlZ2VuZCA9IFRSVUUsIGxlZ2VuZCA9ICJ0b3AiKQoKZ2dzYXZlKCIuL3Bsb3RzL3R1bW9yc0luRGF0YXNldC5wbmciLCBwbG90ID0gZ2dwbG90Mjo6bGFzdF9wbG90KCksIGRwaSA9IDMwMCwgd2lkdGggPSAxMCwgaGVpZ2h0ID0gNikKZ2dzYXZlKCIuL3Bsb3RzL3R1bW9yc0luRGF0YXNldC5wZGYiLCBwbG90ID0gZ2dwbG90Mjo6bGFzdF9wbG90KCksIGRwaSA9IDMwMCwgd2lkdGggPSAxMCwgaGVpZ2h0ID0gNikKCmNmRE5BdnNUaXNzdWVfc2VsZWN0IDwtIGNmRE5BdnNUaXNzdWVfd2l0aEhlYWx0aHkgJT4lIGZpbHRlcihUdW1vclR5cGUgJWluJSBjKCJuZXVyb2JsYXN0b21hIiwgIm5lcGhyb2JsYXN0b21hIiwgIm9zdGVvc2FyY29tYSIsICJyaGFiZG9teW9zYXJjb21hIiwgIkV3aW5nIHNhcmNvbWEiLCAiaGVhbHRoeSIpICYgKGNwYV90eXBlID09ICJDUEFtIikpICU+JSBmaWx0ZXIoYXMubnVtZXJpYyhjZkROQV9ITVdfcmF0aW8pID49IDApCgpyaWRnZXBsb3RfY2ZETkFfcGVyX3R1bW9yIDwtIGdncGxvdCgKICAgY2ZETkF2c1Rpc3N1ZV9zZWxlY3QgJT4lIGZpbHRlcihUdW1vclR5cGUgIT0gImhlYWx0aHkiKSwgCiAgIGFlcyh5ID0gVHVtb3JUeXBlLCB4ID0gY3BhX2NmRE5BLCBmaWxsID0gVHVtb3JUeXBlKSkgKwogICBnZW9tX2RlbnNpdHlfcmlkZ2VzKHNob3cubGVnZW5kID0gRkFMU0UsIHNjYWxlID0gMC44LCBwYW5lbF9zY2FsaW5nID0gRkFMU0UsCiAgICAgICAgICAgICAgICAgICAgICAgcG9pbnRfYWxwaGEgPSAwLjcsIGFscGhhID0gLjIsIHBvaW50X3NoYXBlID0gMSwKICAgICAgICAgICAgICAgICAgICAgICBhZXMocG9pbnRfY29sb3IgPSBUdW1vclR5cGUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHBvaW50X2ZpbGwgPSBUdW1vclR5cGUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHBvaW50X3NpemUgPSBhcy5udW1lcmljKGNmRE5BX0hNV19yYXRpbykpLCAKICAgICAgICAgICAgICAgICAgICAgICBqaXR0ZXJlZF9wb2ludHMgPSBUUlVFLCBwb3NpdGlvbiA9ICJyYWluY2xvdWQiKSArCiAgIHRoZW1lX2J3KCkgKyAKICAgbGFicyhwb2ludF9zaXplID0gImNmRE5BL0hNVyByYXRpbyIsIGZpbGwgPSAidHVtb3IiLCBwb2ludF9maWxsID0gInR1bW9yIiwgcG9pbnRfY29sb3IgPSAidHVtb3IiLCB4ID0gIkNQQW0gY2ZETkEiLCB5ID0gInR1bW9yIikgKyAKICAgZ2VvbV9ib3hwbG90KGFscGhhID0gMC40LCB3aWR0aCA9IDAuMiwgc2hvdy5sZWdlbmQgPSBGQUxTRSwgb3V0bGllci5zaGFwZSA9IE5BKSArIAogICB0aGVtZShsZWdlbmQucG9zaXRpb249InJpZ2h0IikrCiAgIGdlb21fdmxpbmUoZGF0YT1jZkROQXZzVGlzc3VlICU+JSBmaWx0ZXIoY3BhX3R5cGUgPT0gIkNQQW0iKSwgYWxwaGEgPSAwLjYsIGFlcyh4aW50ZXJjZXB0ID0gRkRSX0NQQW0pLCBsaW5ldHlwZSA9ICJkYXNoZWQiKSsKICAgYW5ub3RhdGUoInJlY3QiLHhtaW4gPSAwLCB4bWF4ID0gRkRSX0NQQW0sIHltaW4gPSAtSW5mLCB5bWF4ID0gSW5mLCBhbHBoYT0wLjMsIGZpbGw9ImdyZXkiKSAgKyBsaW1zKHggPSBjKDAsTkEpKQoKCnJpZGdlcGxvdF90aXNzdWVETkFfcGVyX3R1bW9yIDwtIGdncGxvdCgKICAgY2ZETkF2c1Rpc3N1ZV9zZWxlY3QgJT4lIGZpbHRlcihUdW1vclR5cGUgIT0gImhlYWx0aHkiKSwgCiAgIGFlcyh5ID0gVHVtb3JUeXBlLCB4ID0gY3BhX3R1bW9yRE5BLCBmaWxsID0gVHVtb3JUeXBlKSkgKwogICBnZW9tX2RlbnNpdHlfcmlkZ2VzKHNob3cubGVnZW5kID0gRkFMU0UsIHNjYWxlID0gMC44LCBwYW5lbF9zY2FsaW5nID0gRkFMU0UsCiAgICAgICAgICAgICAgICAgICAgICAgcG9pbnRfYWxwaGEgPSAwLjcsIGFscGhhID0gLjIsIHBvaW50X3NoYXBlID0gMSwKICAgICAgICAgICAgICAgICAgICAgICBhZXMocG9pbnRfY29sb3IgPSBUdW1vclR5cGUsIHBvaW50X2ZpbGwgPSBUdW1vclR5cGUpLCBqaXR0ZXJlZF9wb2ludHMgPSBUUlVFLCBwb3NpdGlvbiA9ICJyYWluY2xvdWQiKSArCiAgIHRoZW1lX2J3KCkgKyAKICAgbGFicyh5PSIiLCBwb2ludF9zaXplID0gImNmRE5BL0hNVyByYXRpbyIsIGZpbGwgPSAidHVtb3IiLCBwb2ludF9maWxsID0gInR1bW9yIiwgcG9pbnRfY29sb3IgPSAidHVtb3IiLCB4ID0gIkNQQW0gdHVtb3JETkEiLCB5ID0gInR1bW9yIikgKyAKICAgZ2VvbV9ib3hwbG90KGFscGhhID0gMC40LCB3aWR0aCA9IDAuMiwgc2hvdy5sZWdlbmQgPSBGQUxTRSwgb3V0bGllci5zaGFwZSA9IE5BKSArIAogICB0aGVtZShsZWdlbmQucG9zaXRpb249InJpZ2h0IikgKyB0aGVtZShheGlzLnRleHQueSA9IGVsZW1lbnRfYmxhbmsoKSkKYGBgCgojIyBJbXBhY3Qgb24gbmV1cm9ibGFzdG9tYSByaXNrIHN0cmF0aWZpY2F0aW9uIHsudGFic2V0fQojIyMgQWxsIHNhbXBsZXMKCmBgYHtyfQpNWUNOIDwtIHNhbXBsZV9hbm5vdGF0aW9uICU+JSBkcGx5cjo6ZmlsdGVyKE1ZQ05fYW1wbGlmaWNhdGlvbl9jZkROQSAhPSAiTkEiICYgTVlDTl9hbXBsaWZpY2F0aW9uX3R1bW9yICE9ICJOQSIpCnNqdC54dGFiKE1ZQ04kTVlDTl9hbXBsaWZpY2F0aW9uX2NmRE5BLCBNWUNOJE1ZQ05fYW1wbGlmaWNhdGlvbl90dW1vciwgdmFyLmxhYmVscz1jKCJjZkROQSIsICJ0dW1vciIpLCB2YWx1ZS5sYWJlbHMgPSBsaXN0KGMoIk1ZQ04gbmV1dHJhbCIsICJNWUNOIGdhaW4iKSwgYygiTVlDTiBuZXV0cmFsIiwgIk1ZQ04gZ2FpbiIpKSwgc2hvdy5jZWxsLnByYyA9IFRSVUUsIHNob3cucm93LnByYyA9IFRSVUUsIHNob3cuY29sLnByYyA9IFRSVUUpCmBgYAoKIyMjIGNmRE5BL0hNVyByYXRpbyBhYm92ZSAxCmBgYHtyfQpNWUNOX2hpZ2hxdWFsIDwtIE1ZQ04gJT4lIGRwbHlyOjpmaWx0ZXIoY2ZETkFfSE1XX3JhdGlvID4gMSkKc2p0Lnh0YWIoTVlDTl9oaWdocXVhbCRNWUNOX2FtcGxpZmljYXRpb25fY2ZETkEsIE1ZQ05faGlnaHF1YWwkTVlDTl9hbXBsaWZpY2F0aW9uX3R1bW9yLCB2YXIubGFiZWxzPWMoImNmRE5BIiwgInR1bW9yIiksIHZhbHVlLmxhYmVscyA9IGxpc3QoYygiTVlDTiBuZXV0cmFsIiwgIk1ZQ04gZ2FpbiIpLCBjKCJNWUNOIG5ldXRyYWwiLCAiTVlDTiBnYWluIikpLCBzaG93LmNlbGwucHJjID0gVFJVRSwgc2hvdy5yb3cucHJjID0gVFJVRSwgc2hvdy5jb2wucHJjID0gVFJVRSkKYGBgCgoKIyMgSW1wYWN0IG9uIDFxIGdhaW4gaW4gbmVwaHJvYmxhc3RvbWEKIyMjIEFsbCBzYW1wbGVzCgpgYGB7cn0KbmVwaHJfMXEgPC0gc2FtcGxlX2Fubm90YXRpb24gJT4lIGRwbHlyOjpmaWx0ZXIoYGdhaW5fMXFfV1RfY2ZETkFgICE9ICJOQSIgJiBgZ2Fpbl8xcV9XVF90dW1vcmAgICE9ICJOQSIpCnNqdC54dGFiKG5lcGhyXzFxJGBnYWluXzFxX1dUX2NmRE5BYCwgbmVwaHJfMXEkYGdhaW5fMXFfV1RfdHVtb3JgICwgdmFyLmxhYmVscz1jKCJjZkROQSIsICJ0dW1vciIpLCB2YWx1ZS5sYWJlbHMgPSBsaXN0KGMoIjFxIG5ldXRyYWwiLCAiMXEgZ2FpbiIpLCBjKCIxcSBuZXV0cmFsIiwgIjFxIGdhaW4iKSksIHNob3cuY2VsbC5wcmMgPSBUUlVFLCBzaG93LnJvdy5wcmMgPSBUUlVFLCBzaG93LmNvbC5wcmMgPSBUUlVFKQpgYGAKCiMjIyBjZkROQS9ITVcgcmF0aW8gYWJvdmUgMQpgYGB7cn0KbmVwaHJfMXFfaGlnaHF1YWwgPC0gbmVwaHJfMXEgJT4lIGRwbHlyOjpmaWx0ZXIoY2ZETkFfSE1XX3JhdGlvID4gMSkKc2p0Lnh0YWIobmVwaHJfMXFfaGlnaHF1YWwkYGdhaW5fMXFfV1RfY2ZETkFgLCBuZXBocl8xcV9oaWdocXVhbCRgZ2Fpbl8xcV9XVF90dW1vcmAgLCB2YXIubGFiZWxzPWMoImNmRE5BIiwgInR1bW9yIiksIHZhbHVlLmxhYmVscyA9IGxpc3QoYygiMXEgbmV1dHJhbCIsICIxcSBnYWluIiksIGMoIjFxIG5ldXRyYWwiLCAiMXEgZ2FpbiIpKSwgc2hvdy5jZWxsLnByYyA9IFRSVUUsIHNob3cucm93LnByYyA9IFRSVUUsIHNob3cuY29sLnByYyA9IFRSVUUpCmBgYAoKIyBHZW5lcmFsaXplZCBBZGRpdGl2ZSBNb2RlbGxpbmcKIyMgRGF0YSBjbGVhbmluZwoKCmBgYHtyfQpsaWJyYXJ5KHNqUGxvdCkKbGlicmFyeShnYW1tNCkKbGlicmFyeShsbWU0KQpsaWJyYXJ5KGxtZXJUZXN0KQpsaWJyYXJ5KG1nY3YpCmxpYnJhcnkodGlkeW12KQpsaWJyYXJ5KG1nY1ZpeikKCgpjZkROQV9HQU0gPC0gTDJSY29tcGFyaXNvbiAlPiUgc2VsZWN0KFVuaXF1ZUlELCB0dW1vckROQV9hc3NheV9kZXRhaWwsIFR1bW9yVHlwZSwgY2ZETkFfSE1XX3JhdGlvLCBQYXRpZW50SUQsIG1ldGFzdGF0aWMsIG1lYW5fYWJzX2RpZmZfbG9nMiwgIENGRF9JRCwgIEwyUl9jZkROQSwgTDJSX3R1bW9yRE5BLCBUdW1vckdyb3VwLCBpZCwgcGxhc21hX3ByZXBfcHJvdG9jb2wsIHR1bW9yRE5BX2Fzc2F5X2RldGFpbCkKCmNmRE5BX0dBTSA8LSBjZkROQV9HQU0gICU+JSBmaWx0ZXIoVHVtb3JUeXBlICVpbiUgYyhzYW1wbGVfYW5ub3RhdGlvbiAgJT4lIGdyb3VwX2J5KFR1bW9yVHlwZSkgJT4lIGNvdW50KCkgJT4lIGZpbHRlcihuID49IDUpICU+JSBwdWxsKFR1bW9yVHlwZSkpKSAlPiUgZmlsdGVyKFR1bW9yR3JvdXAgIT0gImJyYWluIHR1bW9yIikKCmNmRE5BX0dBTSRUdW1vclR5cGUgPC0gZ3N1YigiICIsICIiLCBjZkROQV9HQU0kVHVtb3JUeXBlKQpjZkROQV9HQU0kdHVtb3JETkFfYXNzYXlfZGV0YWlsIDwtIGdzdWIoIiAiLCAiIiwgY2ZETkFfR0FNJHR1bW9yRE5BX2Fzc2F5X2RldGFpbCkKY2ZETkFfR0FNJG1ldGFzdGF0aWMgPC0gZ3N1YigiICIsICIiLCBjZkROQV9HQU0kbWV0YXN0YXRpYykKY2ZETkFfR0FNJGlkIDwtIGFzLmZhY3RvcihjZkROQV9HQU0kaWQpCgpgYGAKCi0gTnVtYmVyIG9mIHRvdGFsIG9ic2VydmF0aW9ucyBgciBjZkROQV9HQU0gJT4lIG5yb3coKWAKCmBgYHtyfQpjZkROQV9HQU0gPC0gY2ZETkFfR0FNICAlPiUgZmlsdGVyKG1ldGFzdGF0aWMgIT0gIk5BIikKYGBgCgotIE5VbWJlciBvZiBvYnNlcnZhdGlvbnMgYWZ0ZXIgcmVtb3ZpbmcgYWxsIE5BczogYHIgY2ZETkFfR0FNICU+JSBmaWx0ZXIoIWlzLm5hKG1lYW5fYWJzX2RpZmZfbG9nMikgJiAhaXMubmEoY2ZETkFfSE1XX3JhdGlvKSAmICFpcy5uYSh0dW1vckROQV9hc3NheV9kZXRhaWwpICYgIWlzLm5hKG1ldGFzdGF0aWMpKSAlPiUgbnJvdygpYAoKYGBge3J9CmNmRE5BX0dBTSRUdW1vclR5cGUgPC0gYXMuZmFjdG9yKGNmRE5BX0dBTSRUdW1vclR5cGUpCmNmRE5BX0dBTSRQYXRpZW50SUQgPC0gYXMuZmFjdG9yKGNmRE5BX0dBTSRQYXRpZW50SUQpCmNmRE5BX0dBTSRVbmlxdWVJRCA8LSBhcy5mYWN0b3IoY2ZETkFfR0FNJFVuaXF1ZUlEKQpjZkROQV9HQU0kbWV0YXN0YXRpYyA8LSBhcy5mYWN0b3IoY2ZETkFfR0FNJG1ldGFzdGF0aWMpCmNmRE5BX0dBTSRjZkROQV9ITVdfcmF0aW9fbG9nMTAgPC0gbG9nMTAoY2ZETkFfR0FNJGNmRE5BX0hNV19yYXRpbykjICsgMC4wMDEpCmNmRE5BX0dBTSR0dW1vckROQV9hc3NheV9kZXRhaWwgPC0gYXMuZmFjdG9yKGNmRE5BX0dBTSR0dW1vckROQV9hc3NheV9kZXRhaWwpCmNmRE5BX0dBTSRwbGFzbWFfcHJlcF9wcm90b2NvbCA8LSBhcy5mYWN0b3IoY2ZETkFfR0FNJHBsYXNtYV9wcmVwX3Byb3RvY29sKQoKY2ZETkFfR0FNJHF1YWxpdHlfc2NvcmUgPC0gaWZlbHNlKGNmRE5BX0dBTSRjZkROQV9ITVdfcmF0aW8gPCAxLCAibG93IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShjZkROQV9HQU0kY2ZETkFfSE1XX3JhdGlvIDwgNSAmIGNmRE5BX0dBTSRjZkROQV9ITVdfcmF0aW8gPiAxLCAibWVkaXVtIiwgImhpZ2giKSkKY2ZETkFfR0FNJHF1YWxpdHlfc2NvcmUgPC0gYXMuZmFjdG9yKGNmRE5BX0dBTSRxdWFsaXR5X3Njb3JlKQoKY2ZETkFfR0FNJEwyUl90dW1vckROQSA8LSBzY2FsZShjZkROQV9HQU0kTDJSX3R1bW9yRE5BLCBzY2FsZSA9IEZBTFNFKQpjZkROQV9HQU0kTDJSX2NmRE5BIDwtIHNjYWxlKGNmRE5BX0dBTSRMMlJfY2ZETkEsIHNjYWxlID0gRkFMU0UpCmBgYAoKIyMgTW9kZWwgc3BlY2lmaWNhdGlvbgpgYGB7cn0KaWYgKCFmaWxlLmV4aXN0cygiTDJSY2ZETkFfbW9kZWxfc2ltcGxlLnJkYSIpKXsKICAgTW9kZWwgPC0gYmFtKEwyUl9jZkROQSB+IEwyUl90dW1vckROQSpjZkROQV9ITVdfcmF0aW9fbG9nMTAgKyBMMlJfdHVtb3JETkEqVHVtb3JUeXBlICsgTDJSX3R1bW9yRE5BKm1ldGFzdGF0aWMgKyBzKFBhdGllbnRJRCwgYnMgPSAicmUiKSwgZGF0YSA9IGNmRE5BX0dBTSwgbnRocmVhZHMgPSAzLCBmYW1pbHkgPSBzY2F0KCksIGRpc2NyZXRlID0gVFJVRSwgbWV0aG9kID0gImZSRU1MIiwgZ2MubGV2ZWwgPSAyLCBkcm9wLmludGVyY2VwdCA9IEZBTFNFKQogICBzYXZlUkRTKE1vZGVsLCAiTDJSY2ZETkFfbW9kZWxfc2ltcGxlLnJkYSIpCn0gZWxzZSB7CiAgIE1vZGVsIDwtIHJlYWRSRFMoIkwyUmNmRE5BX21vZGVsX3NpbXBsZS5yZGEiKQp9CmBgYAoKIyMgU3VtbWFyeQpgYGB7cn0KI3N1bW1hcnkoTW9kZWwpCgojcGxvdF9tb2RlbChNb2RlbCwgc2hvdy52YWx1ZXMgPSBUUlVFLCB2YWx1ZS5vZmZzZXQgPSAuMykKCnBsb3RfbW9kZWwoTW9kZWwsIHR5cGUgPSAiZXN0IikgKyB0aGVtZV9idygpCmdnc2F2ZSgiZXN0LnBuZyIsIHBsb3QgPC0gZ2dwbG90Mjo6bGFzdF9wbG90KCksIHdpZHRoID0gMTAsIGhlaWdodCA9IDEwKQoKcGxvdF9tb2RlbChNb2RlbCwgdHlwZSA9ICJwcmVkIikrIHRoZW1lX2J3KCkKZ2dzYXZlKCJwcmVkLnBuZyIsIHBsb3QgPC0gZ2dwbG90Mjo6bGFzdF9wbG90KCksIHdpZHRoID0gMTAsIGhlaWdodCA9IDEwKQoKI3F1YWxfaW50ZXJhY3Rpb24gPC0gcGxvdF9tb2RlbChNb2RlbCwgdHlwZSA9ICJwcmVkIiwgdGVybXMgPSBjKCJMMlJfdHVtb3JETkEiLCJjZkROQV9ITVdfcmF0aW9fbG9nMTAgWzA6MSBieSA9IDAuMV0iKSkgKyBnZW9tX2FibGluZShzbG9wZSA9IDEsIGludGVyY2VwdCA9IDAsIGxpbmV0eXBlID0gImRhc2hlZCIpKyB0aGVtZV9idygpICsgbGFicyhjb2wgPSAiY2ZETkEvSE1XIHJhdGlvIChsb2cxMCkiLCB0aXRsZSA9ICJwcmVkaWN0ZWQgdmFsdWVzIG9mIGxvZzIocmF0aW8pIGluIGNmRE5BIiwgeSA9ICJsb2cyKHJhdGlvKSBpbiBjZkROQSIsIHggPSAibG9nMihyYXRpbykgaW4gdHVtb3IgRE5BIikKbGlicmFyeShnZ2VmZmVjdHMpCm15ZGYgPC0gZ2dwcmVkaWN0KE1vZGVsLHRlcm1zID0gYygiTDJSX3R1bW9yRE5BIiwiY2ZETkFfSE1XX3JhdGlvX2xvZzEwIFswOjIgYnkgPSAwLjA4XSIpKQoKcXVhbF9pbnRlcmFjdGlvbiA8LSAgZ2dwbG90KG15ZGYsIGFlcyh4LCBwcmVkaWN0ZWQsIGdyb3VwID0gZ3JvdXAsIGNvbCA9IGFzLm51bWVyaWMoZ3JvdXApKSkgKwogICBnZW9tX2xpbmUoc2l6ZSA9IDQpICsgdGhlbWVfYncoKSArIGxhYnMoY29sID0gImNmRE5BL0hNVyByYXRpbyAobG9nMTApIiwgdGl0bGUgPSAicHJlZGljdGVkIHZhbHVlcyBvZiBsb2cyKHJhdGlvKSBpbiBjZkROQSIsIHkgPSAibG9nMihyYXRpbykgaW4gY2ZETkEiLCB4ID0gImxvZzIocmF0aW8pIGluIHR1bW9yIEROQSIpKyBnZW9tX2FibGluZShzbG9wZSA9IDEsIGludGVyY2VwdCA9IDAsIGxpbmV0eXBlID0gImRhc2hlZCIpCgpnZ3NhdmUoInByZWRfcmF0aW8ucG5nIiwgcGxvdCA8LSBnZ3Bsb3QyOjpsYXN0X3Bsb3QoKSwgd2lkdGggPSAxMCwgaGVpZ2h0ID0gMTApCgpwbG90X21vZGVsKE1vZGVsLCB0eXBlID0gInByZWQiLCB0ZXJtcyA9IGMoIkwyUl90dW1vckROQSIsICJUdW1vclR5cGUiKSkrIGdlb21fYWJsaW5lKHNsb3BlID0gMSwgaW50ZXJjZXB0ID0gMCwgbGluZXR5cGUgPSAiZGFzaGVkIikrIHRoZW1lX2J3KCkKZ2dzYXZlKCJwcmVkX3R5cGUucG5nIiwgcGxvdCA8LSBnZ3Bsb3QyOjpsYXN0X3Bsb3QoKSwgd2lkdGggPSAxMCwgaGVpZ2h0ID0gMTApCgpwbG90X21vZGVsKE1vZGVsLCB0eXBlID0gInByZWQiLCB0ZXJtcyA9IGMoIlR1bW9yVHlwZSIsICJMMlJfdHVtb3JETkEgWy0wLjEsIDAgLCAwLjFdIikpKyB0aGVtZV9idygpCmdnc2F2ZSgicHJlZF90eXBlMi5wbmciLCBwbG90IDwtIGdncGxvdDI6Omxhc3RfcGxvdCgpLCB3aWR0aCA9IDEwLCBoZWlnaHQgPSAxMCkKCnBsb3RfbW9kZWwoTW9kZWwsIHR5cGUgPSAicHJlZCIsIHRlcm1zID0gYygiTDJSX3R1bW9yRE5BIiwgIm1ldGFzdGF0aWMiKSkgKyBnZW9tX2FibGluZShzbG9wZSA9IDEsIGludGVyY2VwdCA9IDAsIGxpbmV0eXBlID0gImRhc2hlZCIpKyB0aGVtZV9idygpCmdnc2F2ZSgicHJlZF9tZXRhLnBuZyIsIHBsb3QgPC0gZ2dwbG90Mjo6bGFzdF9wbG90KCksIHdpZHRoID0gMTAsIGhlaWdodCA9IDEwKQoKcGxvdF9tb2RlbChNb2RlbCwgdHlwZSA9ICJwcmVkIiwgdGVybXMgPSBjKCJtZXRhc3RhdGljIiwgIkwyUl90dW1vckROQSBbLTAuMSwgMCAsIDAuMV0iKSkrIHRoZW1lX2J3KCkKZ2dzYXZlKCJwcmVkX21ldGEyLnBuZyIsIHBsb3QgPC0gZ2dwbG90Mjo6bGFzdF9wbG90KCksIHdpZHRoID0gMTAsIGhlaWdodCA9IDEwKQoKI3Bsb3RfbW9kZWwoTW9kZWwsIHR5cGUgPSAic2xvcGUiLCBzaG93LmxvZXNzID0gRkFMU0UpKyB0aGVtZV9idygpCiNnZ3NhdmUoInByZWRfc2xvcGUucG5nIiwgcGxvdCA8LSBnZ3Bsb3QyOjpsYXN0X3Bsb3QoKSwgd2lkdGggPSAxMCwgaGVpZ2h0ID0gMTApCgojcGxvdF9tb2RlbChNb2RlbCwgdHlwZSA9ICJyZXNpZCIsIHNob3cubG9lc3MgPSBGQUxTRSkrIHRoZW1lX2J3KCkKI2dnc2F2ZSgicHJlZF9yZXNpZC5wbmciLCBwbG90IDwtIGdncGxvdDI6Omxhc3RfcGxvdCgpLCB3aWR0aCA9IDEwLCBoZWlnaHQgPSAxMCkKYGBgCgojIyBWaXN1YWxpc2F0aW9uIG9mIGFzc3VtcHRpb25zCmBgYHtyfQp2IDwtIGdldFZpeihNb2RlbCkKcHJpbnQocGxvdCh2KSArIGxfcG9pbnRzKCkgKyBsX2ZpdExpbmUoKSwgcGFnZXMgPSAxKQoKY2hlY2sodiwgYS5oaXN0ID0gbGlzdChiaW5zICA9IDEwMCksIGEucmVzcG9pID0gbGlzdChhbHBoYSA9IDAuMSkpCmBgYAoKIyMgUmVncmVzc2lvbiBjb2VmZmljaWVudCB0YWJsZQoKYGBge3J9CnRhYl9tb2RlbChNb2RlbCwgc2hvdy5yZWZsdmwgPSBUUlVFLCBkaWdpdHMgPSA0LCAgZmlsZSA9ICJ0YWJsZV9HQU0uaHRtbCIpCmBgYAoKCiMgSGVhdG1hcCB7LnRhYnNldH0KCmBgYHtyfQoKZGZfaGVhdG1hcF9pbml0ID0gZGZfaGVhdG1hcF9pbml0ICU+JSBzZWxlY3QoLWMobWVhbkxvZzIpKQoKIyBwYXJhbXMgdG8gdGVzdCBmdW5jdGlvbiB3aXRoCiNzYW1wbGVfc2VsZWN0IDwtIGMoIm9zdGVvc2FyY29tYSIsICJFd2luZyBzYXJjb21hIiwgInJoYWJkb215b3NhcmNvbWEiKQojd2lkdGhfcHggPSAxMjAwCiNoZWlnaHRfcHggPSAxODAwCiNzYW1wbGVfc2VsZWN0IDwtICJuZXVyb2JsYXN0b21hIgoKbWFrZUhlYXRtYXAgPC0gZnVuY3Rpb24oZGZfaGVhdG1hcF9pbml0LCBzYW1wbGVfc2VsZWN0LCB3aWR0aF9weCwgaGVpZ2h0X3B4LCBhcnJhbmdlaG0gPSAidHVtb3IiKXsKICAgI2RmX2hlYXRtYXAgPSBkZl9oZWF0bWFwX2luaXQgJT4lIGZpbHRlcihzdHJfZGV0ZWN0KFNhbXBsZUlELCBuZXVyb2JsYXN0b21hKSkKICAgZGZfaGVhdG1hcCA8LSBkZl9oZWF0bWFwX2luaXQKICAgZGZfaGVhdG1hcCRiaW4gPC0gcGFzdGUwKGFzLmNoYXJhY3RlcihkZl9oZWF0bWFwJGNociksICI6IiwgYXMuY2hhcmFjdGVyKGRmX2hlYXRtYXAkc3RhcnQpLCAiLSIsIGFzLmNoYXJhY3RlcihkZl9oZWF0bWFwJGVuZCkpCiAgIAogICAjIGZpbmQgY2F1c2Ugb2YgZHVwbGljYXRlcwogICBkZl9oZWF0bWFwIDwtIGRmX2hlYXRtYXAgJT4lIHNlbGVjdCgtYyhjaHIsIHN0YXJ0LCBlbmQpKSAlPiUgZ3JvdXBfYnkoU2FtcGxlSUQpICU+JSBkaXN0aW5jdChiaW4sIC5rZWVwX2FsbCA9IFRSVUUpICU+JSB1bmdyb3VwKCkgJT4lIHNwcmVhZChrZXkgPSBjKGJpbiksIHZhbHVlID0gcmF0aW8pCiAgIGRmX2hlYXRtYXAgPC0gZGZfaGVhdG1hcCAlPiUgCiAgICAgIHNlbGVjdCh3aGVyZSh+IWFueShpcy5uYSguKSkpKQogICAjZGZfaGVhdG1hcCA8LSBkZl9oZWF0bWFwICU+JSBkaXN0aW5jdChTYW1wbGVJRCwgLmtlZXBfYWxsID0gVFJVRSkKICAgCiAgIGNvbG5hbWVzX2htIDwtIHBhc3RlMChnc3ViKCI6LioiLCAiIiwgY29sbmFtZXMoZGZfaGVhdG1hcFssMjpuY29sKGRmX2hlYXRtYXApXSkpKQogICBjb2xuYW1lc19obSA8LSBmYWN0b3IoY29sbmFtZXNfaG0sIGxldmVscyA9IGNocl9vcmRlcikKICAgcm93bmFtZXNfaG0gPC0gZGZfaGVhdG1hcCRTYW1wbGVJRAogICAKICAgCiAgIHNhbXBsZVR5cGVzIDwtIHNhbXBsZV9hbm5vdGF0aW9uX2xvbmcgJT4lIGZpbHRlcihTYW1wbGVJRCAgJWluJSByb3duYW1lc19obSkKICAgCiAgIHNhbXBsZVR5cGVzIDwtIHNhbXBsZVR5cGVzICU+JSBkcGx5cjo6YXJyYW5nZShQYXRpZW50SUQpCiAgIAogICBkZl9oZWF0bWFwIDwtIGlubmVyX2pvaW4oc2FtcGxlVHlwZXMsIGRmX2hlYXRtYXApCiAgIGlmIChhcnJhbmdlaG0gPT0gInBlYXJzb25SIil7CiAgICAgIGRmX2hlYXRtYXAgPC0gZGZfaGVhdG1hcCAlPiUgZHBseXI6OmFycmFuZ2UoZGVzYyhwZWFyc29uUiksUGF0aWVudElELCBUdW1vclR5cGUpCiAgIH1lbHNlewogICAgICBkZl9oZWF0bWFwIDwtIGRmX2hlYXRtYXAgJT4lIGRwbHlyOjphcnJhbmdlKFBhdGllbnRJRCwgVHVtb3JUeXBlKQogICB9CiAgIGRmX2hlYXRtYXAgPC0gZGZfaGVhdG1hcCAlPiUgZGlzdGluY3QoU2FtcGxlSUQsIGAxOjEwMDQwMDAwMS0xMDA2MDAwMDBgLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBgMToxMDcyMDAwMDEtMTA3NDAwMDAwYCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBgMToxMTMwMDAwMDEtMTEzMjAwMDAwYCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBgMToxMTc4MDAwMDEtMTE4MDAwMDAwYCwgLmtlZXBfYWxsID0gVFJVRSkKICAgaWYgKGFycmFuZ2VobSA9PSAicGVhcnNvblIiKXsKICAgICAgZGZfaGVhdG1hcCA8LSBkZl9oZWF0bWFwICU+JSBmaWx0ZXIoUGF0aWVudElEICVpbiUgc2FtcGxlX3NlbGVjdCkKICAgfSBlbHNlewogICAgICBkZl9oZWF0bWFwIDwtIGRmX2hlYXRtYXAgJT4lIGZpbHRlcihUdW1vclR5cGUgJWluJSBzYW1wbGVfc2VsZWN0KQogICB9CiAgIAogICBkZl9oZWF0bWFwJHBlYXJzb25SIDwtIHJvdW5kKGRmX2hlYXRtYXAkcGVhcnNvblIsIDIpCiAgICNkZl9oZWF0bWFwJHBlYXJzb25SIDwtIGlmZWxzZShkZl9oZWF0bWFwJGJpb21hdGVyaWFsID09ICJjZkROQSIsIE5BLCBkZl9oZWF0bWFwJHBlYXJzb25SKQogICAjICAgIGNiaW5kKHNhbXBsZV9hbm5vdGF0aW9uJHNXR1MsIHNhbXBsZV9hbm5vdGF0aW9uJFR1bW9yVHlwZSwgcmVwKCJzV0dTIiwgbnJvdyhzYW1wbGVfYW5ub3RhdGlvbikpKSwKICAgIyAgICBjYmluZChzYW1wbGVfYW5ub3RhdGlvbiRhcnJheSwgc2FtcGxlX2Fubm90YXRpb24kVHVtb3JUeXBlLCByZXAoImFycmF5IiwgbnJvdyhzYW1wbGVfYW5ub3RhdGlvbikpKQogICAjICkpCiAgICMgY29sbmFtZXMoc2FtcGxlVHlwZXMpIDwtIGMoIlNhbXBsZUlEIiwgInR1bW9yIiwgInR5cGUiKQogICAKICAgaHRfb3B0KAogICAgICBsZWdlbmRfdGl0bGVfZ3AgPSBncGFyKGZvbnRzaXplID0gMjAsIGZvbnRmYWNlID0gImJvbGQiKSwKICAgICAgbGVnZW5kX2xhYmVsc19ncCA9IGdwYXIoZm9udHNpemUgPSAyMCksCiAgICAgIFJPV19BTk5PX1BBRERJTkcgPSB1bml0KDgsIm1tIikKICAgKQogICAKICAgdHVtb3JfY29sIDwtIGNvbG9yUmFtcFBhbGV0dGUoY29sb3JzID0gYnJld2VyLnBhbCgxMiwgIlBhaXJlZCIpKSAobGVuZ3RoKGxldmVscyhhcy5mYWN0b3IoZGZfaGVhdG1hcCRUdW1vclR5cGUpKSkpCiAgIG5hbWVzKHR1bW9yX2NvbCkgPC0gbGV2ZWxzKGFzLmZhY3RvcihkZl9oZWF0bWFwJFR1bW9yVHlwZSkpCiAgIAogICBwbGF0Zm9ybV9jb2wgPC0gY29sb3JSYW1wUGFsZXR0ZShjb2xvcnMgPSBicmV3ZXIucGFsKDksICJTZXQxIikpIChsZW5ndGgobGV2ZWxzKGFzLmZhY3RvcihkZl9oZWF0bWFwJGFzc2F5RGV0YWlsKSkpKQogICBuYW1lcyhwbGF0Zm9ybV9jb2wpIDwtIGxldmVscyhhcy5mYWN0b3IoZGZfaGVhdG1hcCRhc3NheURldGFpbCkpCiAgIAogICBiaW9tYXRfY29sIDwtIGNvbG9yUmFtcFBhbGV0dGUoY29sb3JzID0gYnJld2VyLnBhbCgzLCAiU2V0MyIpKSAobGVuZ3RoKGxldmVscyhhcy5mYWN0b3IoZGZfaGVhdG1hcCRiaW9tYXRlcmlhbCkpKSkKICAgbmFtZXMoYmlvbWF0X2NvbCkgPC0gbGV2ZWxzKGFzLmZhY3RvcihkZl9oZWF0bWFwJGJpb21hdGVyaWFsKSkKICAgCiAgIHNvdXJjZV9jb2wgPC0gY29sb3JSYW1wUGFsZXR0ZShjb2xvcnMgPSBicmV3ZXIucGFsKDUsICJTZXQyIikpIChsZW5ndGgobGV2ZWxzKGFzLmZhY3RvcihkZl9oZWF0bWFwJHNvdXJjZSkpKSkKICAgbmFtZXMoc291cmNlX2NvbCkgPC0gbGV2ZWxzKGFzLmZhY3RvcihkZl9oZWF0bWFwJHNvdXJjZSkpCiAgIAogICBwZWFyc29uUl9jb2wgPC0gY29sb3JSYW1wMihjKC0wLjEsIDEpLCBjb2xvcnMgPSBjKCJ3aGl0ZSIsICJwdXJwbGUiKSkKICAgCiAgIGhhID0gSGVhdG1hcEFubm90YXRpb24oCiAgICAgIENQQW0gPSBhbm5vX2JhcnBsb3QoZGZfaGVhdG1hcCRDUEFtLCBncCA9IGdwYXIoZmlsbCA9IDIsIGNvbCA9IDIpKSwKICAgICAgcGVhcnNvblIgPSBkZl9oZWF0bWFwJHBlYXJzb25SLAogICAgICBwbGF0Zm9ybSA9IGRmX2hlYXRtYXAkYXNzYXlEZXRhaWwsCiAgICAgIGNvbCA9IGxpc3QocGxhdGZvcm0gPSBwbGF0Zm9ybV9jb2wsIGJpb21hdGVyaWFsID0gYmlvbWF0X2NvbCwgdHVtb3IgPSB0dW1vcl9jb2wsIHNvdXJjZSA9IHNvdXJjZV9jb2wpLAogICAgICBiaW9tYXRlcmlhbCA9IGRmX2hlYXRtYXAkYmlvbWF0ZXJpYWwsCiAgICAgIHR1bW9yID0gZGZfaGVhdG1hcCRUdW1vclR5cGUsCiAgICAgIHNvdXJjZSAgPSBkZl9oZWF0bWFwJHNvdXJjZSwKICAgICAgYW5ub3RhdGlvbl9uYW1lX3NpZGUgPSAiYm90dG9tIiwgd2hpY2ggPSAicm93Iiwgc2hvd19sZWdlbmQgPSBUUlVFLAogICAgICB3aWR0aCA9IHVuaXQoNiwgImNtIiksCiAgICAgIGdhcCA9IHVuaXQoMC41LCAibW0iKSwKICAgICAgc2hvd19hbm5vdGF0aW9uX25hbWUgPSBUUlVFLAogICAgICBzaW1wbGVfYW5ub19zaXplID0gdW5pdCgwLjgsICJjbSIpLAogICAgICBhbm5vdGF0aW9uX2xlZ2VuZF9wYXJhbSA9IAogICAgICAgICBsaXN0KAogICAgICAgICAgICBwbGF0Zm9ybSA9IGxpc3QoCiAgICAgICAgICAgICAgIHRpdGxlID0gInBsYXRmb3JtIgogICAgICAgICAgICApLAogICAgICAgICAgICBiaW9tYXRlcmlhbCA9IGxpc3QoCiAgICAgICAgICAgICAgIHRpdGxlID0gImJpb21hdGVyaWFsIgogICAgICAgICAgICApLAogICAgICAgICAgICB0dW1vciA9IGxpc3QoCiAgICAgICAgICAgICAgIHRpdGxlID0gInR1bW9yIiwgCiAgICAgICAgICAgICAgIG5jb2wgPSAxCiAgICAgICAgICAgICksCiAgICAgICAgICAgIHNvdXJjZSA9IGxpc3QoCiAgICAgICAgICAgICAgIHRpdGxlID0gInNvdXJjZSIsIAogICAgICAgICAgICAgICBuY29sID0gMQogICAgICAgICAgICApCiAgICAgICAgICkpCiAgIAogICBsb3NzIDwtIHdlc19wYWxldHRlKCJaaXNzb3UxIilbMV0KICAgZ2FpbiA8LSB3ZXNfcGFsZXR0ZSgiWmlzc291MSIpWzVdCiAgIG5ldXRyYWwgPC0gIiNGMUYxRjEiCiAgIGhtX3EgPC0gcXVhbnRpbGUoZGZfaGVhdG1hcFssMTI6bmNvbChkZl9oZWF0bWFwKV0sIG5hLnJtID0gVFJVRSwgcHJvYnMgPSBjKDAuMDEsIDAuOTkpKQogICBjb2xfZnVuID0gY29sb3JSYW1wMihjKGhtX3FbMV0sIDAsIGhtX3FbMl0pLCBjKGxvc3MsIG5ldXRyYWwsIGdhaW4pKQogICAKCiAgIAogICBpZiAoYXJyYW5nZWhtID09ICJwZWFyc29uUiIpewogICAgICBobV9kZiA8LSBhcy5tYXRyaXgoZGZfaGVhdG1hcFssMTI6bmNvbChkZl9oZWF0bWFwKV0pCiAgICAgIHJvd25hbWVzKGhtX2RmKSA8LSBhcy5mYWN0b3IoZGZfaGVhdG1hcCRwZWFyc29uUikKICAgICAgYXJyIDwtIG9yZGVyKChyb3duYW1lcyhobV9kZikpKQogICAgICBzcGxpdCA8LSBjKHJlcCgxLCBucm93KGhtX2RmKS8yKSwgcmVwKDIsIG5yb3coaG1fZGYpLzIpKQogICAgICByb3dfZ2FwIDwtIDUKICAgICAgZmlsZW5hbWUgPC0gIl9wZWFyc29uUl8iCiAgICAgIGhtX2RmIDwtIGhtX2RmWywyOm5jb2woaG1fZGYpXQogICB9IGVsc2UgewogICAgICBobV9kZiA8LSBhcy5tYXRyaXgoZGZfaGVhdG1hcFssMTM6bmNvbChkZl9oZWF0bWFwKV0pCiAgICAgIHJvd25hbWVzKGhtX2RmKSA8LSBhcy5mYWN0b3IoZGZfaGVhdG1hcCRwZWFyc29uUikKICAgICAgYXJyIDwtIE5VTEwKICAgICAgc3BsaXQgPC0gZGZfaGVhdG1hcCRQYXRpZW50SUQKICAgICAgcm93X2dhcCA8LSAwLjQKICAgICAgZmlsZW5hbWUgPC0gIl9ieXR1bW9yXyIKICAgfQogICBodCA8LSBIZWF0bWFwKGhtX2RmLCAKICAgICAgICAgICAgICAgICBuYW1lID0gImxvZzJyYXRpbyIsIGNvbHVtbl9zcGxpdCA9IGNvbG5hbWVzX2htLCByb3dfc3BsaXQgPSBzcGxpdCwKICAgICAgICAgICAgICAgICBjb2wgPSAgIGNvbF9mdW4sCiAgICAgICAgICAgICAgICAgcm93X3RpdGxlID0gRkFMU0UsCiAgICAgICAgICAgICAgICAgcm93X2dhcCA9IHVuaXQocm93X2dhcCwgIm1tIiksCiAgICAgICAgICAgICAgICAgY2x1c3Rlcl9jb2x1bW5zID0gRkFMU0UsIAogICAgICAgICAgICAgICAgIGNsdXN0ZXJfcm93cyA9IEZBTFNFLAogICAgICAgICAgICAgICAgIHNob3dfY29sdW1uX25hbWVzID0gRkFMU0UsCiAgICAgICAgICAgICAgICAgc2hvd19yb3dfbmFtZXMgPSBUUlVFLCAKICAgICAgICAgICAgICAgICByb3dfbGFiZWxzID0gZGZfaGVhdG1hcCRQYXRpZW50SUQsIAogICAgICAgICAgICAgICAgIHJvd19vcmRlciA9IGFyciwKICAgICAgICAgICAgICAgICByaWdodF9hbm5vdGF0aW9uID0gaGEsCiAgICAgICAgICAgICAgICAgY29sdW1uX3RpdGxlX2dwID0gZ3Bhcihmb250c2l6ZSA9IDEwKSwKICAgICAgICAgICAgICAgICBjb2x1bW5fZ2FwID0gdW5pdCgxLCAibW0iKSkKICAgcG5nKHBhc3RlMChwbG90Zm9sZGVyLCAiaGVhdG1hcCIsIGZpbGVuYW1lLCBzYW1wbGVfc2VsZWN0WzFdLCAiLnBuZyIpLCB3aWR0aCA9IHdpZHRoX3B4LCBoZWlnaHQgPSBoZWlnaHRfcHgsIHBvaW50c2l6ZSA9IDE0ICkKICAgbWFwIDwtIGRyYXcoaHQsIGhlYXRtYXBfbGVnZW5kX3NpZGUgPSAiYm90dG9tIikKICAgZGV2Lm9mZigpCiAgIAp9CmxpYnJhcnkoZGF0YS50YWJsZSkKCiMgdG8gYWRkIG1pZGRsZSAxMAojcGVhcnNvbl92ZWN0IDwtIGMoc2FtcGxlX2Fubm90YXRpb25fbG9uZyAlPiUgYXJyYW5nZShkZXNjKHBlYXJzb25SKSkgJT4lIGhlYWQobiA9IDIwKSAlPiUgcHVsbChQYXRpZW50SUQpLCBzZXRvcmRlcihkYXRhLnRhYmxlKHNhbXBsZV9hbm5vdGF0aW9uX2xvbmcpLCBwZWFyc29uUilbKC5OLzIgLSAyMC8yKTooLk4vMiArIDIwLzIgLSAxKSwgXSAlPiUgcHVsbChQYXRpZW50SUQpLCBzYW1wbGVfYW5ub3RhdGlvbl9sb25nICU+JSBhcnJhbmdlKGRlc2MocGVhcnNvblIpKSAlPiUgZmlsdGVyKCFpcy5uYShwZWFyc29uUikpICU+JSB0YWlsKG4gPSAyMCkgJT4lIHB1bGwoUGF0aWVudElEKSkKCnBlYXJzb25fdmVjdCA8LSBjKHNhbXBsZV9hbm5vdGF0aW9uX2xvbmcgJT4lIGZpbHRlcihQYXRpZW50SUQgIT0gInBhdGllbnRfMTAxIikgJT4lIGFycmFuZ2UoZGVzYyhwZWFyc29uUikpICU+JSBoZWFkKG4gPSAzMCkgJT4lIHB1bGwoUGF0aWVudElEKSwgc2FtcGxlX2Fubm90YXRpb25fbG9uZyAlPiUgZmlsdGVyKFBhdGllbnRJRCAhPSAicGF0aWVudF8xMDEiKSAlPiUgYXJyYW5nZShkZXNjKHBlYXJzb25SKSkgJT4lIGZpbHRlcighaXMubmEocGVhcnNvblIpKSAlPiUgdGFpbChuID0gMzApICU+JSBwdWxsKFBhdGllbnRJRCkpCgptYWtlSGVhdG1hcChkZl9oZWF0bWFwX2luaXQgPSBkZl9oZWF0bWFwX2luaXQsIHBlYXJzb25fdmVjdCwgd2lkdGhfcHggPSAxMjAwLCBoZWlnaHRfcHggPSAxNDAwLCBhcnJhbmdlaG0gPSAicGVhcnNvblIiKQpgYGAKCiMjIEFkcmVuYWwgdHVtb3JzCgpgYGB7cn0KbWFrZUhlYXRtYXAoZGZfaGVhdG1hcF9pbml0ID0gZGZfaGVhdG1hcF9pbml0LCBjKCJuZXVyb2JsYXN0b21hIiwgImdhbmdsaW9uZXVyb2JsYXN0b21hIiksIHdpZHRoX3B4ID0gMTIwMCwgaGVpZ2h0X3B4ID0gMjIwMCkKYGBgCgohW2hlYXRtYXAgbmV1cm9ibGFzdG9tYSBhbmQgZ2FuZ2xpb25ldXJvYmxhc3RvbWFdKC9Vc2Vycy9ybXZwYWVtZS9SZXBvcy9SVlBDVlAyMDEyX3NXR1MvcGxvdHMvaGVhdG1hcF9ieXR1bW9yX25ldXJvYmxhc3RvbWEucG5nKQoKIyMgU2FyY29tYXMKCmBgYHtyfQptYWtlSGVhdG1hcChkZl9oZWF0bWFwX2luaXQgPSBkZl9oZWF0bWFwX2luaXQsIGMoIm9zdGVvc2FyY29tYSIsICJFd2luZyBzYXJjb21hIiwgInJoYWJkb215b3NhcmNvbWEiKSwgd2lkdGhfcHggPSAxMjAwLCBoZWlnaHRfcHggPSAxMDAwKQpgYGAKCgohW2hlYXRtYXAgcmhhYmRvbXlvc2FyY29tYSwgRXdpbmcgc2FyY29tYSBhbmQgcmhhYmRvbXlvc2FyY29tYV0oL1VzZXJzL3JtdnBhZW1lL1JlcG9zL1JWUENWUDIwMTJfc1dHUy9wbG90cy9oZWF0bWFwX2J5dHVtb3Jfb3N0ZW9zYXJjb21hLnBuZykKCiMjIEtpZG5leSB0dW1vcnMKCmBgYHtyfQptYWtlSGVhdG1hcChkZl9oZWF0bWFwX2luaXQgPSBkZl9oZWF0bWFwX2luaXQsIGMoIm5lcGhyb2JsYXN0b21hIiwgImtpZG5leSBzYXJjb21hIiwgIm1hbGlnbmFudCByaGFiZG9pZCB0dW1vciBvZiB0aGUga2lkbmV5IiwgInJlbmFsIGNlbGwgY2FyY2lub21hIiksIHdpZHRoX3B4ID0gMTIwMCwgaGVpZ2h0X3B4ID0gMTIwMCkKYGBgCgohW2hlYXRtYXAgbmVwaHJvYmxhc3RvbWEsIGtpZG5leSBzYXJjb21hLCBNUlRLIGFuZCBSQ0NdKC9Vc2Vycy9ybXZwYWVtZS9SZXBvcy9SVlBDVlAyMDEyX3NXR1MvcGxvdHMvaGVhdG1hcF9ieXR1bW9yX25lcGhyb2JsYXN0b21hLnBuZykKCiMjIEJyYWluIHR1bW9ycwoKYGBge3J9Cm1ha2VIZWF0bWFwKGRmX2hlYXRtYXBfaW5pdCA9IGRmX2hlYXRtYXBfaW5pdCwgYygibWVkdWxsb2JsYXN0b21hIiwgIkFUUlQiLCAiUE5FVCIsICJhc3Ryb2N5dGljIHBpbG9jeXRvbWEiLCAiZXBlbmR5bW9tYSIsICJnYW5nbGlvZ2xpb21hIiwgImdsaW9ibGFzdG9tYSIsICJoZW1hbmdpb2JsYXN0b21hIiwgIm1lbmluZ2VvbWEiKSwgd2lkdGhfcHggPSAxMjAwLCBoZWlnaHRfcHggPSA4MDApCmBgYAoKIVtoZWF0bWFwIGJyYWluIHR1bW9yc10oL1VzZXJzL3JtdnBhZW1lL1JlcG9zL1JWUENWUDIwMTJfc1dHUy9wbG90cy9oZWF0bWFwX2J5dHVtb3JfbWVkdWxsb2JsYXN0b21hLnBuZykKCgojIEhldGVyZW9nZW5laXR5IHBsb3RzCgohW2V4YW1wbGUgaGV0ZXJvZ2VuZWl0eSBwbG90IGJlZm9yZSBwaWN0dXJlcyBvZiByZXNlY3Rpb24gYXJlIGFkZGVkXSgvVXNlcnMvcm12cGFlbWUvUmVwb3MvUlZQQ1ZQMjAxMl9zV0dTL3Bsb3RzL3BhdGllbnRfMDU3X0NGRDE4MDY4NTJfMkcwNV9oZXRlcm9nZW4ucG5nKQoKCmBgYHtyLCBpbmNsdWRlID0gRkFMU0UsIGVjaG8gPSBGQUxTRX0KZGF0YWRpcl9zV0dTX2NmRE5BIDwtICIuL2RhdGEvc1dHU19jZkROQS8iCmRhdGFkaXJfc1dHU190aXNzdWUgPC0gIi4vZGF0YS9zV0dTX3Rpc3N1ZS8iCmRhdGFkaXJfYXJyYXlCRSA8LSAiLi9kYXRhL2FycmF5LyIKZGF0YWRpcl9hcnJheUNaIDwtICIuL2RhdGEvU05QYXJyYXkvIgpiaW5zaXplID0gIjIwMGtiIgoKZGF0YWRpcjEgPSBkYXRhZGlyX3NXR1NfY2ZETkEKZGF0YWRpcjIgPSBkYXRhZGlyX2FycmF5Q1oKc2FtcGxlMSA9ICJDRkQxODA2ODUxIgpzYW1wbGUyID0gIjJTODgiCnNhbXBsZTMgPSAiMlM4OSIKc2FtcGxlNCA9ICIyUzkwIgoKbGlicmFyeShnZ3RleHQpCm1ha2VDTlZjb21wYXJpc29uIDwtIGZ1bmN0aW9uKGRhdGFkaXIxLCBkYXRhZGlyMiwgc2FtcGxlMSwgc2FtcGxlMiwgc2FtcGxlMywgc2FtcGxlNCwgcGF0aWVudElEKXsKICAgCiAgIAogICBiaW5zX3NhbXBsZTEgPC0gcmVhZF90c3YocGFzdGUwKGRhdGFkaXIxLCBzdHJfc3Vic2V0KGRpcihkYXRhZGlyMSwgcGF0dGVybiA9IHNhbXBsZTEpLCAiYmluc19tYXNrIikpLCBjb2xfdHlwZXMgPSBjKCJmZGQ/ZCIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sX25hbWVzID0gYygiY2hyIiwgInN0YXJ0IiwgImVuZCIsICJpZCIsICJyYXRpbyIpLCBza2lwID0gMSkKICAgYmluc19zYW1wbGUxIDwtIGJpbnNfc2FtcGxlMSAlPiUgZmlsdGVyKCFjaHIgJWluJSBjKCJYIiwgIlkiLCAiMjMiLCAiMjQiKSkKICAgCiAgIAogICBiaW5zX3NhbXBsZTIgPC0gIHJlYWRfdHN2KHBhc3RlMChkYXRhZGlyMiwiLyIsc2FtcGxlMiwiXyIsIGJpbnNpemUsICIudHN2IiksIGNvbF90eXBlcyA9IGMoImZkZGQiKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xfbmFtZXMgPSBjKCJjaHIiLCAic3RhcnQiLCAiZW5kIiwgInJhdGlvIikpCiAgIGJpbnNfc2FtcGxlMiA8LSBiaW5zX3NhbXBsZTIgJT4lIGZpbHRlcighY2hyICVpbiUgYygiWCIsICJZIiwgIjIzIiwgIjI0IikpCiAgIGJpbnNfc2FtcGxlMiRjaHIgPC0gZmFjdG9yKGJpbnNfc2FtcGxlMiRjaHIsIGxldmVscyA9IGNocl9vcmRlcikKICAgCiAgIGJpbnNfc2FtcGxlMyA8LSAgcmVhZF90c3YocGFzdGUwKGRhdGFkaXIyLCIvIixzYW1wbGUzLCJfIiwgYmluc2l6ZSwgIi50c3YiKSwgY29sX3R5cGVzID0gYygiZmRkZCIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbF9uYW1lcyA9IGMoImNociIsICJzdGFydCIsICJlbmQiLCAicmF0aW8iKSkKICAgYmluc19zYW1wbGUzIDwtIGJpbnNfc2FtcGxlMyAlPiUgZmlsdGVyKCFjaHIgJWluJSBjKCJYIiwgIlkiLCAiMjMiLCAiMjQiKSkKICAgYmluc19zYW1wbGUzJGNociA8LSBmYWN0b3IoYmluc19zYW1wbGUzJGNociwgbGV2ZWxzID0gY2hyX29yZGVyKQogICAKICAgYmluc19zYW1wbGU0IDwtICByZWFkX3RzdihwYXN0ZTAoZGF0YWRpcjIsIi8iLHNhbXBsZTQsIl8iLCBiaW5zaXplLCAiLnRzdiIpLCBjb2xfdHlwZXMgPSBjKCJmZGRkIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sX25hbWVzID0gYygiY2hyIiwgInN0YXJ0IiwgImVuZCIsICJyYXRpbyIpKQogICBiaW5zX3NhbXBsZTQgPC0gYmluc19zYW1wbGU0ICU+JSBmaWx0ZXIoIWNociAlaW4lIGMoIlgiLCAiWSIsICIyMyIsICIyNCIpKQogICBiaW5zX3NhbXBsZTQkY2hyIDwtIGZhY3RvcihiaW5zX3NhbXBsZTQkY2hyLCBsZXZlbHMgPSBjaHJfb3JkZXIpCiAgIAogICBzZWdzX3NhbXBsZTEgPC0gcmVhZF90c3YocGFzdGUwKGRhdGFkaXIxLCBzdHJfc3Vic2V0KGRpcihkYXRhZGlyMSwgcGF0dGVybiA9IHNhbXBsZTEpLCAic2VnbWVudHNfbWFzay5iZWQiKSksIGNvbF90eXBlcyA9IGMoImZkZGRkIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xfbmFtZXMgPSBjKCJjaHIiLCAic3RhcnQiLCAiZW5kIiwgInJhdGlvIiwgInpzY29yZSIpKQogICBzZWdzX3NhbXBsZTEgPC0gc2Vnc19zYW1wbGUxICU+JSBmaWx0ZXIoIWNociAlaW4lIGMoIlgiLCAiWSIsICIyMyIsICIyNCIpKSAlPiUgbXV0YXRlKFNhbXBsZSA9IHNhbXBsZTEpCiAgIAogICAKICAgc2Vnc19zYW1wbGUyIDwtIHJlYWRfdHN2KHBhc3RlMChkYXRhZGlyMiwiLyIsc2FtcGxlMiwiX3NlZ21lbnRzX3Blcl8iLCBiaW5zaXplLCAiX21hc2sudHN2IiksIGNvbF90eXBlcyA9IGMoImZkZGQiKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbF9uYW1lcyA9IGMoImNociIsICJzdGFydCIsICJlbmQiLCAicmF0aW8iKSwgc2tpcCA9IDEpCiAgIAogICBzZWdzX3NhbXBsZTIgPC0gc2Vnc19zYW1wbGUyICU+JSBmaWx0ZXIoIWNociAlaW4lIGMoIlgiLCAiWSIsICIyMyIsICIyNCIpKSAlPiUgbXV0YXRlKFNhbXBsZSA9IHNhbXBsZTIpCiAgIHNlZ3Nfc2FtcGxlMiRjaHIgPC0gZmFjdG9yKHNlZ3Nfc2FtcGxlMiRjaHIsIGxldmVscyA9IGNocl9vcmRlcikKICAgCiAgIHNlZ3Nfc2FtcGxlMyA8LSByZWFkX3RzdihwYXN0ZTAoZGF0YWRpcjIsIi8iLHNhbXBsZTMsIl9zZWdtZW50c19wZXJfIiwgYmluc2l6ZSwgIl9tYXNrLnRzdiIpLCBjb2xfdHlwZXMgPSBjKCJmZGRkIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xfbmFtZXMgPSBjKCJjaHIiLCAic3RhcnQiLCAiZW5kIiwgInJhdGlvIiksIHNraXAgPSAxKQogICAKICAgc2Vnc19zYW1wbGUzIDwtIHNlZ3Nfc2FtcGxlMyAlPiUgZmlsdGVyKCFjaHIgJWluJSBjKCJYIiwgIlkiLCAiMjMiLCAiMjQiKSkgJT4lIG11dGF0ZShTYW1wbGUgPSBzYW1wbGUyKQogICBzZWdzX3NhbXBsZTMkY2hyIDwtIGZhY3RvcihzZWdzX3NhbXBsZTMkY2hyLCBsZXZlbHMgPSBjaHJfb3JkZXIpCiAgIAogICBzZWdzX3NhbXBsZTQgPC0gcmVhZF90c3YocGFzdGUwKGRhdGFkaXIyLCIvIixzYW1wbGU0LCJfc2VnbWVudHNfcGVyXyIsIGJpbnNpemUsICJfbWFzay50c3YiKSwgY29sX3R5cGVzID0gYygiZmRkZCIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sX25hbWVzID0gYygiY2hyIiwgInN0YXJ0IiwgImVuZCIsICJyYXRpbyIpLCBza2lwID0gMSkKICAgCiAgIHNlZ3Nfc2FtcGxlNCA8LSBzZWdzX3NhbXBsZTQgJT4lIGZpbHRlcighY2hyICVpbiUgYygiWCIsICJZIiwgIjIzIiwgIjI0IikpICU+JSBtdXRhdGUoU2FtcGxlID0gc2FtcGxlMikKICAgc2Vnc19zYW1wbGU0JGNociA8LSBmYWN0b3Ioc2Vnc19zYW1wbGU0JGNociwgbGV2ZWxzID0gY2hyX29yZGVyKQogICAKICAgY29sb3JfY2ZETkEgPC0gd2VzX3BhbGV0dGUoIkNhdmFsY2FudGkxIilbMV0KICAgY29sb3JfdHVtb3JETkEgPC0gd2VzX3BhbGV0dGUoIkNhdmFsY2FudGkxIilbNF0KICAgY29sb3JfYWJiZXJhdGlvbnMgPC0gd2VzX3BhbGV0dGUoIkNhdmFsY2FudGkxIilbNV0KICAgCiAgIGNvbF9zMSA8LSB3ZXNfcGFsZXR0ZSgiUm95YWwxIilbMV0KICAgY29sX3MyIDwtIHdlc19wYWxldHRlKCJSb3lhbDEiKVsyXQogICBjb2xfczMgPC0gd2VzX3BhbGV0dGUoIlJveWFsMiIpWzRdCiAgIGNvbF9zNCA8LSB3ZXNfcGFsZXR0ZSgiUm95YWwxIilbNF0KICAgCiAgIAogICBjcGFfczEgPC0gcm91bmQoZ2V0LmNwYS5tb2RpZmllZDIoc2Vnc19zYW1wbGUxKSw0KQogICBjcGFfczIgPC0gcm91bmQoZ2V0LmNwYS5tb2RpZmllZDIoc2Vnc19zYW1wbGUyKSw0KQogICBjcGFfczMgPC0gcm91bmQoZ2V0LmNwYS5tb2RpZmllZDIoc2Vnc19zYW1wbGUzKSw0KQogICBjcGFfczQgPC0gcm91bmQoZ2V0LmNwYS5tb2RpZmllZDIoc2Vnc19zYW1wbGU0KSw0KQogICAKICAgY29ycGxvdF9kZl9iaW5zIDwtIGlubmVyX2pvaW4oYmluc19zYW1wbGUxLCBiaW5zX3NhbXBsZTIsIGJ5ID0gYygiY2hyIiwgInN0YXJ0IiwgImVuZCIpKQogICBjb3JwbG90X2RmX2JpbnMgPC0gaW5uZXJfam9pbihjb3JwbG90X2RmX2JpbnMsIGJpbnNfc2FtcGxlMywgYnkgPSBjKCJjaHIiLCAic3RhcnQiLCAiZW5kIikpCiAgIGNvcnBsb3RfZGZfYmlucyA8LSBpbm5lcl9qb2luKGNvcnBsb3RfZGZfYmlucywgYmluc19zYW1wbGU0LCBieSA9IGMoImNociIsICJzdGFydCIsICJlbmQiKSkKICAgI2NvcnBsb3RfZGYgPC0gY29ycGxvdF9kZiAlPiUgZmlsdGVyKCFpcy5uYShyYXRpby54KSAmICFpcy5uYShyYXRpby55KSkKICAgCiAgIGNvcnBsb3RfZGZfYmlucyA8LSBjb3JwbG90X2RmX2JpbnMgJT4lCiAgICAgIG11dGF0ZShyTS5zMT1yb2xsYXBwbHkocmF0aW8ueCwxMDAsIEZVTj1mdW5jdGlvbih4KSBtZWFuKHgsIG5hLnJtPVRSVUUpLCBmaWxsPU5BLCBhbGlnbj0icmlnaHQiKSkgJT4lCiAgICAgIG11dGF0ZShyTS5zMj1yb2xsYXBwbHkocmF0aW8ueSwxMDAsIEZVTj1mdW5jdGlvbih4KSBtZWFuKHgsIG5hLnJtPVRSVUUpLCBmaWxsPU5BLCBhbGlnbj0icmlnaHQiKSkgICU+JQogICAgICBtdXRhdGUock0uczM9cm9sbGFwcGx5KHJhdGlvLngueCwxMDAsIEZVTj1mdW5jdGlvbih4KSBtZWFuKHgsIG5hLnJtPVRSVUUpLCBmaWxsPU5BLCBhbGlnbj0icmlnaHQiKSkgICU+JQogICAgICBtdXRhdGUock0uczQ9cm9sbGFwcGx5KHJhdGlvLnkueSwxMDAsIEZVTj1mdW5jdGlvbih4KSBtZWFuKHgsIG5hLnJtPVRSVUUpLCBmaWxsPU5BLCBhbGlnbj0icmlnaHQiKSkgCiAgIAogICBtYXgucmF0aW9fcm9sbCA8LSBtYXgoYyhjb3JwbG90X2RmX2JpbnMkcmF0aW8ueCwgY29ycGxvdF9kZl9iaW5zJHJhdGlvLnksIGNvcnBsb3RfZGZfYmlucyRyYXRpby54LngsIGNvcnBsb3RfZGZfYmlucyRyYXRpby55LnkpLCBuYS5ybSA9IFRSVUUpCiAgIG1pbi5yYXRpb19yb2xsIDwtIG1pbihjKGNvcnBsb3RfZGZfYmlucyRyYXRpby54LCBjb3JwbG90X2RmX2JpbnMkcmF0aW8ueSwgY29ycGxvdF9kZl9iaW5zJHJhdGlvLngueCwgY29ycGxvdF9kZl9iaW5zJHJhdGlvLnkueSksIG5hLnJtID0gVFJVRSkKICAgCiAgIGNvbG9ycyA8LSBjKCJjZkROQSIgPSBjb2xfczEsICJsb2NhdGlvbiAxIiA9IGNvbF9zMiwgImxvY2F0aW9uIDIiID0gY29sX3MzLCAibG9jYXRpb24gMyIgPSBjb2xfczQpCiAgIAogICAjcGF0aWVudElEX3RpdGxlIDwtIGdzdWIoInAiLCAiUCIsIHBhdGllbnRJRCkKICAgcGF0aWVudElEX3RpdGxlIDwtIGdzdWIoIl8iLCAiICIsIHBhdGllbnRJRCkKICAgCiAgIHJvbGxtZWFuIDwtIGdncGxvdCh0aWJibGUoY29ycGxvdF9kZl9iaW5zKSwgYWVzKHggPSBzdGFydCkpICsgCiAgICAgIHRoZW1lX2J3KCkgKyAKICAgICAgbGFicyh5ID0gImxvZzIocmF0aW8pIiwgeCA9ICJjaHJvbW9zb21lcyIpICsgbGltcyh5ID0gYygtMSwxKSkgKwogICAgICBnZW9tX2xpbmUoYWVzKHk9ck0uczEsIGNvbCA9ICJjZkROQSIpLCBhbHBoYSA9IDEsIHNpemUgPSAwLjYpICsKICAgICAgZ2VvbV9saW5lKGFlcyh5PXJNLnMyLCBjb2wgPSAibG9jYXRpb24gMSIpLCBhbHBoYSA9IDAuOCwgc2l6ZSA9IDAuNikgKwogICAgICBnZW9tX2xpbmUoYWVzKHk9ck0uczMsIGNvbCA9ICJsb2NhdGlvbiAyIiksIGFscGhhID0gMSwgc2l6ZSA9IDAuNikgKwogICAgICBnZW9tX2xpbmUoYWVzKHk9ck0uczQsIGNvbCA9ICJsb2NhdGlvbiAzIiksIGFscGhhID0gMC44LCBzaXplID0gMC42KSArCiAgICAgIHRoZW1lKHBhbmVsLnNwYWNpbmcueCA9IHVuaXQoMCwgImxpbmVzIiksCiAgICAgICAgICAgIHBhbmVsLnNwYWNpbmcueSA9IHVuaXQoMCwgImxpbmVzIiksCiAgICAgICAgICAgICMgIGF4aXMudGl0bGUueCA9ICBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgICAgIGF4aXMudGV4dC54ID0gIGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgICAgYXhpcy50aWNrcy54ID0gIGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgICAgc3RyaXAuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChjb2xvciA9ICJ3aGl0ZSIsIGZpbGwgPSAid2hpdGUiKSwKICAgICAgICAgICAgcGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgICAgcGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgICAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSkgKyAKICAgICAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCwgbGluZXR5cGUgPSAiZGFzaGVkIiwgY29sID0gImdyYXkiKSArCiAgICAgIGZhY2V0X3dyYXAofmNociwgc3RyaXAucG9zaXRpb24gPSAiYm90dG9tIiwgc2NhbGVzID0iZnJlZV94IiwgbnJvdyA9IDEpK2xhYnMoY29sID0gTlVMTCkgKwogICAgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gY29sb3JzKSArIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iKSArCiAgICAgIGxhYnMoCiAgICAgICAgIHRpdGxlID0gcGFzdGUwKHBhdGllbnRJRF90aXRsZSwgIgogICAgICAgICAgICAgICAgICAgICAgXG4iLAogICAgICAgICAgICAgICAgICAgICAgIjxzcGFuPiBDUEFtOgogICAgICAgPHNwYW4gc3R5bGU9J2NvbG9yOiIsY29sX3MxICwiOyc+Iiwgcm91bmQoY3BhX3MxLDIpLCAiPC9zcGFuPiAtIAogICAgICAgPHNwYW4gc3R5bGU9J2NvbG9yOiIsY29sX3MyICwiOyc+Iiwgcm91bmQoY3BhX3MyLDIpLCAiPC9zcGFuPiAtCiAgICAgICA8c3BhbiBzdHlsZT0nY29sb3I6Iixjb2xfczMgLCI7Jz4iLCByb3VuZChjcGFfczMsMiksICI8L3NwYW4+IC0KICAgICAgIDxzcGFuIHN0eWxlPSdjb2xvcjoiLGNvbF9zNCAsIjsnPiIsIHJvdW5kKGNwYV9zNCwyKSwgIjwvc3Bhbj4KICAgICAgIDwvc3Bhbj4iCiAgICAgICAgICkpKwogICAgICB0aGVtZSgKICAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfbWFya2Rvd24obGluZWhlaWdodCA9IDEuMSksCiAgICAgICAgIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF9tYXJrZG93bihzaXplID0gMTUpLAogICAgICAgICBsZWdlbmQua2V5LnNpemUgPSB1bml0KDMsImxpbmUiKQogICAgICApCiAgICMgKyBsaW1zKHkgPSBjKC1OQSxOQSkpCiAgIAogICAKICAgZ2dzYXZlKHBhc3RlMChwbG90Zm9sZGVyLCBwYXRpZW50SUQsICJfIiwgc2FtcGxlMSwgIl8iLCBzYW1wbGUyLCAiX2hldGVyb2dlbi5wbmciKSwgcGxvdCA9IHJvbGxtZWFuLCB3aWR0aCA9IDEwLCBoZWlnaHQgPSA0LCBkcGkgPSAzMDApCn0KCmRhdGFkaXIxID0gZGF0YWRpcl9zV0dTX2NmRE5BCmRhdGFkaXIyID0gZGF0YWRpcl9hcnJheUNaCnNhbXBsZTEgPSAiQ0ZEMTgwNjg1MSIKc2FtcGxlMiA9ICIyUzg4IgpzYW1wbGUzID0gIjJTODkiCnNhbXBsZTQgPSAiMlM5MCIKcGF0aWVudElEID0gc2FtcGxlX2Fubm90YXRpb25fZnVsbCAlPiUgZmlsdGVyKHR1bW9yRE5BX0lEID09IHNhbXBsZTIpICU+JSBwdWxsKFBhdGllbnRJRCkKbWFrZUNOVmNvbXBhcmlzb24oZGF0YWRpcjEsIGRhdGFkaXIyLCBzYW1wbGUxLCBzYW1wbGUyLCBzYW1wbGUzLCBzYW1wbGU0LCBwYXRpZW50SUQpCgpzYW1wbGUxID0gIkNGRDE4MDY4NTIiCnNhbXBsZTIgPSAiMkcwNSIKc2FtcGxlMyA9ICIyRzA2IgpzYW1wbGU0ID0gIjJHMDciCnBhdGllbnRJRCA9IHNhbXBsZV9hbm5vdGF0aW9uX2Z1bGwgJT4lIGZpbHRlcih0dW1vckROQV9JRCA9PSBzYW1wbGUyKSAlPiUgcHVsbChQYXRpZW50SUQpCm1ha2VDTlZjb21wYXJpc29uKGRhdGFkaXIxLCBkYXRhZGlyMiwgc2FtcGxlMSwgc2FtcGxlMiwgc2FtcGxlMywgc2FtcGxlNCwgcGF0aWVudElEKQoKCgptYWtlQ05WY29tcGFyaXNvbiA8LSBmdW5jdGlvbihkYXRhZGlyMSwgZGF0YWRpcjIsIHNhbXBsZTEsIHNhbXBsZTIsIHNhbXBsZTMsIHNhbXBsZTQpewogICAKICAgYmluc19zYW1wbGUxIDwtIHJlYWRfdHN2KHBhc3RlMChkYXRhZGlyMSwgc3RyX3N1YnNldChkaXIoZGF0YWRpcjEsIHBhdHRlcm4gPSBzYW1wbGUxKSwgImJpbnNfbWFzayIpKSwgY29sX3R5cGVzID0gYygiZmRkP2QiKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbF9uYW1lcyA9IGMoImNociIsICJzdGFydCIsICJlbmQiLCAiaWQiLCAicmF0aW8iKSwgc2tpcCA9IDEpCiAgIGJpbnNfc2FtcGxlMSA8LSBiaW5zX3NhbXBsZTEgJT4lIGZpbHRlcighY2hyICVpbiUgYygiWCIsICJZIiwgIjIzIiwgIjI0IikpCiAgIAogICAKICAgYmluc19zYW1wbGUyIDwtIHJlYWRfdHN2KHBhc3RlMChkYXRhZGlyMiwgc3RyX3N1YnNldChkaXIoZGF0YWRpcjIsIHBhdHRlcm4gPSBzYW1wbGUyKSwgImJpbnNfbWFzayIpKSwgY29sX3R5cGVzID0gYygiZmRkP2QiKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbF9uYW1lcyA9IGMoImNociIsICJzdGFydCIsICJlbmQiLCAiaWQiLCAicmF0aW8iKSwgc2tpcCA9IDEpCiAgIGJpbnNfc2FtcGxlMiA8LSBiaW5zX3NhbXBsZTIgJT4lIGZpbHRlcighY2hyICVpbiUgYygiWCIsICJZIiwgIjIzIiwgIjI0IikpCiAgIGJpbnNfc2FtcGxlMiRjaHIgPC0gZmFjdG9yKGJpbnNfc2FtcGxlMiRjaHIsIGxldmVscyA9IGNocl9vcmRlcikKICAgCiAgIGJpbnNfc2FtcGxlMyA8LSAgcmVhZF90c3YocGFzdGUwKGRhdGFkaXIyLCBzdHJfc3Vic2V0KGRpcihkYXRhZGlyMiwgcGF0dGVybiA9IHNhbXBsZTMpLCAiYmluc19tYXNrIikpLCBjb2xfdHlwZXMgPSBjKCJmZGQ/ZCIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbF9uYW1lcyA9IGMoImNociIsICJzdGFydCIsICJlbmQiLCAiaWQiLCAicmF0aW8iKSwgc2tpcCA9IDEpCiAgIGJpbnNfc2FtcGxlMyA8LSBiaW5zX3NhbXBsZTMgJT4lIGZpbHRlcighY2hyICVpbiUgYygiWCIsICJZIiwgIjIzIiwgIjI0IikpCiAgIGJpbnNfc2FtcGxlMyRjaHIgPC0gZmFjdG9yKGJpbnNfc2FtcGxlMyRjaHIsIGxldmVscyA9IGNocl9vcmRlcikKICAgCiAgIGJpbnNfc2FtcGxlNCA8LSAgcmVhZF90c3YocGFzdGUwKGRhdGFkaXIyLCBzdHJfc3Vic2V0KGRpcihkYXRhZGlyMiwgcGF0dGVybiA9IHNhbXBsZTQpLCAiYmluc19tYXNrIikpLCBjb2xfdHlwZXMgPSBjKCJmZGQ/ZCIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbF9uYW1lcyA9IGMoImNociIsICJzdGFydCIsICJlbmQiLCAiaWQiLCAicmF0aW8iKSwgc2tpcCA9IDEpCiAgIGJpbnNfc2FtcGxlNCA8LSBiaW5zX3NhbXBsZTQgJT4lIGZpbHRlcighY2hyICVpbiUgYygiWCIsICJZIiwgIjIzIiwgIjI0IikpCiAgIGJpbnNfc2FtcGxlNCRjaHIgPC0gZmFjdG9yKGJpbnNfc2FtcGxlNCRjaHIsIGxldmVscyA9IGNocl9vcmRlcikKICAgCiAgIGNvbG9yX2NmRE5BIDwtIHdlc19wYWxldHRlKCJDYXZhbGNhbnRpMSIpWzFdCiAgIGNvbG9yX3R1bW9yRE5BIDwtIHdlc19wYWxldHRlKCJDYXZhbGNhbnRpMSIpWzRdCiAgIGNvbG9yX2FiYmVyYXRpb25zIDwtIHdlc19wYWxldHRlKCJDYXZhbGNhbnRpMSIpWzVdCiAgIAogICBjb2xfczEgPC0gd2VzX3BhbGV0dGUoIlJveWFsMSIpWzFdCiAgIGNvbF9zMiA8LSB3ZXNfcGFsZXR0ZSgiUm95YWwxIilbMl0KICAgY29sX3MzIDwtIHdlc19wYWxldHRlKCJSb3lhbDIiKVs0XQogICBjb2xfczQgPC0gd2VzX3BhbGV0dGUoIlJveWFsMSIpWzRdCiAgIG1heC5yYXRpb19iaW5zIDwtIG1heChjKGJpbnNfc2FtcGxlMSRyYXRpbywgYmluc19zYW1wbGUyJHJhdGlvLCBiaW5zX3NhbXBsZTMkcmF0aW8sIGJpbnNfc2FtcGxlNCRyYXRpbyksIG5hLnJtID0gVFJVRSkKICAgbWluLnJhdGlvX2JpbnMgPC0gbWluKGMoYmluc19zYW1wbGUxJHJhdGlvLCBiaW5zX3NhbXBsZTIkcmF0aW8sIGJpbnNfc2FtcGxlMyRyYXRpbywgYmluc19zYW1wbGU0JHJhdGlvKSwgbmEucm0gPSBUUlVFKQogICAKICAgCiAgIGNvcnBsb3RfZGZfYmlucyA8LSBmdWxsX2pvaW4oYmluc19zYW1wbGUxLCBiaW5zX3NhbXBsZTIsIGJ5ID0gYygiY2hyIiwgInN0YXJ0IiwgImVuZCIpKQogICBjb3JwbG90X2RmX2JpbnMgPC0gZnVsbF9qb2luKGNvcnBsb3RfZGZfYmlucywgYmluc19zYW1wbGUzLCBieSA9IGMoImNociIsICJzdGFydCIsICJlbmQiKSkKICAgY29ycGxvdF9kZl9iaW5zIDwtIGZ1bGxfam9pbihjb3JwbG90X2RmX2JpbnMsIGJpbnNfc2FtcGxlNCwgYnkgPSBjKCJjaHIiLCAic3RhcnQiLCAiZW5kIikpCiAgICNjb3JwbG90X2RmIDwtIGNvcnBsb3RfZGYgJT4lIGZpbHRlcighaXMubmEocmF0aW8ueCkgJiAhaXMubmEocmF0aW8ueSkpCiAgIAogICBjb3JwbG90X2RmX2JpbnMgPC0gY29ycGxvdF9kZl9iaW5zICU+JQogICAgICBtdXRhdGUock0uczE9cm9sbGFwcGx5KHJhdGlvLngsMTAwLCBGVU49ZnVuY3Rpb24oeCkgbWVhbih4LCBuYS5ybT1UUlVFKSwgZmlsbD1OQSwgYWxpZ249InJpZ2h0IikpICU+JQogICAgICBtdXRhdGUock0uczI9cm9sbGFwcGx5KHJhdGlvLnksMTAwLCBGVU49ZnVuY3Rpb24oeCkgbWVhbih4LCBuYS5ybT1UUlVFKSwgZmlsbD1OQSwgYWxpZ249InJpZ2h0IikpICAlPiUKICAgICAgbXV0YXRlKHJNLnMzPXJvbGxhcHBseShyYXRpby54LngsMTAwLCBGVU49ZnVuY3Rpb24oeCkgbWVhbih4LCBuYS5ybT1UUlVFKSwgZmlsbD1OQSwgYWxpZ249InJpZ2h0IikpICAlPiUKICAgICAgbXV0YXRlKHJNLnM0PXJvbGxhcHBseShyYXRpby55LnksMTAwLCBGVU49ZnVuY3Rpb24oeCkgbWVhbih4LCBuYS5ybT1UUlVFKSwgZmlsbD1OQSwgYWxpZ249InJpZ2h0IikpIAogICAKICAgCiAgIGNvbG9ycyA8LSBjKCJFRFRBIHBsYXNtYSIgPSBjb2xfczEsICJTdHJlY2sgcGxhc21hIiA9IGNvbF9zMiwgIkNTRiIgPSBjb2xfczMsICJTdHJlY2sgQ1NGIiA9IGNvbF9zNCkKICAgCiAgIHJvbGxtZWFuIDwtIGdncGxvdCh0aWJibGUoY29ycGxvdF9kZl9iaW5zKSAlPiUgZmlsdGVyKGNociA9PSAiNiIgfCBjaHIgPT0gIjUiIHwgY2hyID09ICI3IiksIGFlcyh4ID0gc3RhcnQpKSArIAogICAgICB0aGVtZV9idygpICsgCiAgICAgIGxhYnMoeSA9ICJsb2cyKHJhdGlvKSIsIHggPSAiY2hyb21vc29tZXMiKSArIGxpbXMoeSA9IGMoLTEsMSkpICsKICAgICAgZ2VvbV9saW5lKGFlcyh5PXJNLnMzLCBjb2wgPSAiRURUQSBwbGFzbWEiKSwgYWxwaGEgPSAwLjcsIHNpemUgPSAwLjYpICsKICAgICAgZ2VvbV9saW5lKGFlcyh5PXJNLnM0LCBjb2wgPSAiU3RyZWNrIHBsYXNtYSIpLCBhbHBoYSA9IDAuNywgc2l6ZSA9IDAuNikgKwogICAgICBnZW9tX2xpbmUoYWVzKHk9ck0uczEsIGNvbCA9ICJDU0YiKSwgYWxwaGEgPSAwLjcsIHNpemUgPSAwLjYpICsKICAgICAgZ2VvbV9saW5lKGFlcyh5PXJNLnMyLCBjb2wgPSAiU3RyZWNrIENTRiIpLCBhbHBoYSA9IDAuNywgc2l6ZSA9IDAuNikgKwogICAgICB0aGVtZShwYW5lbC5zcGFjaW5nLnggPSB1bml0KDAsICJsaW5lcyIpLAogICAgICAgICAgICBwYW5lbC5zcGFjaW5nLnkgPSB1bml0KDAsICJsaW5lcyIpLAogICAgICAgICAgICAjICBheGlzLnRpdGxlLnggPSAgZWxlbWVudF9ibGFuaygpLAogICAgICAgICAgICBheGlzLnRleHQueCA9ICBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgICAgIGF4aXMudGlja3MueCA9ICBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgICAgIHN0cmlwLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoY29sb3IgPSAid2hpdGUiLCBmaWxsID0gIndoaXRlIiksCiAgICAgICAgICAgIHBhbmVsLmdyaWQubWFqb3IgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgICAgIHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X2JsYW5rKCkpICsgCiAgICAgIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDAsIGxpbmV0eXBlID0gImRhc2hlZCIsIGNvbCA9ICJncmF5IikgKwogICAgICBmYWNldF93cmFwKH5jaHIsIHN0cmlwLnBvc2l0aW9uID0gImJvdHRvbSIsIHNjYWxlcyA9ImZyZWVfeCIsIG5yb3cgPSAxKStsYWJzKGNvbCA9IE5VTEwpICsKICAgICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGNvbG9ycykgKyB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIikgKyBsaW1zKHkgPSBjKC0xLDAuMikpCiAgIAogICAKICAgcm9sbG1lYW4gPC0gcm9sbG1lYW4gKyB0aGVtZShsZWdlbmQudGV4dD1lbGVtZW50X3RleHQoc2l6ZT0xNSkpICsgdGhlbWUobGVnZW5kLmtleS5zaXplID0gdW5pdCgzLCJsaW5lIikpCiAgIGdnc2F2ZShwYXN0ZTAocGxvdGZvbGRlciwgcGF0aWVudElELCAiXyIsIHNhbXBsZTEsICJfIiwgc2FtcGxlMiwgIl9DU0YucG5nIiksIHBsb3QgPSByb2xsbWVhbiwgd2lkdGggPSAxMCwgaGVpZ2h0ID0gNCwgZHBpID0gMzAwKQp9CgpkYXRhZGlyMSA9IGRhdGFkaXJfc1dHU19jZkROQQpkYXRhZGlyMiA9IGRhdGFkaXJfc1dHU19jZkROQQpzYW1wbGUxID0gIkNGRDE4MDIyOTEiCnNhbXBsZTIgPSAiQ0ZEMTgwMjI5MiIKc2FtcGxlMyA9ICJNMUE4MDAxMDgiCnNhbXBsZTQgPSAiTU1BMTgwMDAxNiIKbWFrZUNOVmNvbXBhcmlzb24oZGF0YWRpcjEsIGRhdGFkaXIyLCBzYW1wbGUxLCBzYW1wbGUyLCBzYW1wbGUzLCBzYW1wbGU0KQpgYGAKCiMgTWFudXNjcmlwdCBmaWd1cmVzCgpgYGB7ciwgZmlnLndpZHRoID0gNiwgZmlnLmhlaWdodD0gOH0KcCA8LSBnZ2FycmFuZ2UocmlkZ2VwbG90X2NmRE5BX3Blcl90dW1vciwgcmlkZ2VwbG90X3Rpc3N1ZUROQV9wZXJfdHVtb3IsIHF1YWxfaW50ZXJhY3Rpb24gICsgCiAgICAgICAgICAgICAgICAgIHRoZW1lKHN0cmlwLnRleHQueCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgICAgICAgICAgICAgICAgc3RyaXAuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChjb2xvdXI9IndoaXRlIiwgZmlsbD0id2hpdGUiKSwKICAgICAgICAgICAgICAgICAgICAgICAgbGVnZW5kLnBvc2l0aW9uPWMoMC4zLDAuODUpLCBsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDgpLAogICAgICAgICAgICAgICAgICApICArCiAgICAgICAgICAgICAgICAgIHNjYWxlX2NvbG9yX2NvbnRpbnVvdXMoYnJlYWtzID0gYygwLCAxMCwgMjApLCBsYWJlbHMgPSBjKCIxIiwgIjEwIiwgIjEwMCIpKSArIGxhYnModGl0bGUgPSBOVUxMLCBjb2wgPSAiY2ZETkEvSE1XIHJhdGlvIiksIG5jb2wgPSAzLCBsYWJlbHMgPSBjKCJCIiwgIkMiLCAiRCIpLCB3aWR0aHMgPSBjKDAuMzAsMC4yMCwgMC4zMCkpCgpwX2FyciA8LSBnZ2FycmFuZ2UocF9DUEF2c1IsIHAsIG5yb3cgPSAyLCBsYWJlbHMgPSBjKCJBIiksIGNvbW1vbi5sZWdlbmQgPSBGQUxTRSkKCmdnc2F2ZSgiLi9wbG90cy9mYWNldHBsb3QucG5nIiwgcGxvdCA9IGdncGxvdDI6Omxhc3RfcGxvdCgpLCBkcGkgPSAzMDAsIHdpZHRoID0gOSwgaGVpZ2h0ID0gMTMpCmBgYAoKIyBSZXN1bHQgc2VjdGlvbiBpbiBSTWFya2Rvd24KVGhlIHJlc3VsdHMgc2VjdGlvbiB3YXMgd3JpdHRlbiBpbiBSbWFya2Rvd24sIHRoZSBudW1iZXJzIHdlcmUgcHVsbGVkIGltbWVkaWF0ZWx5IGZyb20gdGhlIGRhdGFmcmFtZXMgaW4gdGhpcyBSTWFya2Rvd24gZmlsZS4gRm9yIHRoZSBjb2RlLCBzZWUgdGhlIGAuUm1kYCBmaWxlIChhcyBvcHBvc2VkIHRvIHRoZSBgLmh0bWxgIGZpbGUpLgoKKipTYW1wbGUgY29sbGVjdGlvbi4qKiBXZSByZXRyb3NwZWN0aXZlbHkgaW5jbHVkZWQgYHIgKGNmRE5BdnNUaXNzdWUgJT4lIHB1bGwoQ0ZEX0lEKSAlPiUgdW5pcXVlKCkgJT4lIGxlbmd0aCgpICsgY2ZETkF2c1Rpc3N1ZSAlPiUgcHVsbCh0dW1vckROQV9JRCkgJT4lIHVuaXF1ZSgpICU+JSBsZW5ndGgoKSlgIHVuaXF1ZSBzYW1wbGVzIChuID0gYHIgY2ZETkF2c1Rpc3N1ZSAlPiUgZmlsdGVyKENGRF9iaW9tYXRlcmlhbCA9PSAicGxhc21hIikgJT4lIHB1bGwoQ0ZEX0lEKSAlPiUgdW5pcXVlKCkgJT4lIGxlbmd0aCgpYCBwbGFzbWEsIG4gPSBgciBjZkROQXZzVGlzc3VlICU+JSBmaWx0ZXIoQ0ZEX2Jpb21hdGVyaWFsID09ICJDU0YiKSAlPiUgcHVsbChDRkRfSUQpICU+JSB1bmlxdWUoKSAlPiUgbGVuZ3RoKClgIENTRiwgbiA9IGByIGNmRE5BdnNUaXNzdWUgJT4lIHB1bGwodHVtb3JETkFfSUQpICU+JSB1bmlxdWUoKSAlPiUgbGVuZ3RoKClgIHR1bW9yIHRpc3N1ZSkgb2YgYHIgY2ZETkF2c1Rpc3N1ZSAlPiUgc2VsZWN0KFBhdGllbnRJRCkgJT4lIHVuaXF1ZSAlPiUgbnJvdygpYCB1bmlxdWUgcGVkaWF0cmljIGNhbmNlciBjYXNlcy4gUGF0aWVudHMgd2VyZSByZWNydWl0ZWQgYXQgR2hlbnQgVW5pdmVyc2l0eSBIb3NwaXRhbCAobiA9IGByIGNmRE5BdnNUaXNzdWUgJT4lIGZpbHRlcihTYW1wbGVPcmlnaW4gPT0gIlVaRyIpICU+JSBzZWxlY3QoUGF0aWVudElEKSAlPiUgdW5pcXVlICU+JSBucm93KClgKSwgUHJpbmNlc3MgTcOheGltYSBDZW50ZXIgKG4gPSBgciBjZkROQXZzVGlzc3VlICU+JSBmaWx0ZXIoU2FtcGxlT3JpZ2luID09ICJQTUMiKSAlPiUgc2VsZWN0KFBhdGllbnRJRCkgJT4lIHVuaXF1ZSAlPiUgbnJvdygpYCksIEluc3RpdHV0IEN1cmllIChuID0gYHIgY2ZETkF2c1Rpc3N1ZSAlPiUgZmlsdGVyKFNhbXBsZU9yaWdpbiA9PSAiQ1VSSUUiKSAlPiUgc2VsZWN0KFBhdGllbnRJRCkgJT4lIHVuaXF1ZSAlPiUgbnJvdygpYCkgYW5kIFVuaXZlcnNpdHkgSG9zcGl0YWwgTW90b2wgKG4gPSBgciBjZkROQXZzVGlzc3VlICU+JSBmaWx0ZXIoU2FtcGxlT3JpZ2luID09ICJNSCIpICU+JSBzZWxlY3QoUGF0aWVudElEKSAlPiUgdW5pcXVlICU+JSBucm93KClgKS4gSW4gdG90YWwsIHRoZSBjb2hvcnQgY29tcHJpc2VkIEV3aW5nIHNhcmNvbWEgKG4gPSBgciBjZkROQXZzVGlzc3VlICU+JSBmaWx0ZXIoVHVtb3JUeXBlID09ICJFd2luZyBzYXJjb21hIikgJT4lIHNlbGVjdChQYXRpZW50SUQpICU+JSB1bmlxdWUgJT4lIG5yb3coKWApLCBvc3Rlb3NhcmNvbWEgKG4gPSBgciBjZkROQXZzVGlzc3VlICU+JSBmaWx0ZXIoVHVtb3JUeXBlID09ICJvc3Rlb3NhcmNvbWEiKSAlPiUgc2VsZWN0KFBhdGllbnRJRCkgJT4lIHVuaXF1ZSAlPiUgbnJvdygpYCksIHJoYWJkb215b3NhcmNvbWEgKG4gPSBgciBjZkROQXZzVGlzc3VlICU+JSBmaWx0ZXIoVHVtb3JUeXBlID09ICJyaGFiZG9teW9zYXJjb21hIikgJT4lIHNlbGVjdChQYXRpZW50SUQpICU+JSB1bmlxdWUgJT4lIG5yb3coKWApLCBuZXBocm9ibGFzdG9tYSAobiA9IGByIGNmRE5BdnNUaXNzdWUgJT4lIGZpbHRlcihUdW1vclR5cGUgPT0gIm5lcGhyb2JsYXN0b21hIikgJT4lIHNlbGVjdChQYXRpZW50SUQpICU+JSB1bmlxdWUgJT4lIG5yb3coKWApLCBuZXVyb2JsYXN0b21hIChuID0gYHIgY2ZETkF2c1Rpc3N1ZSAlPiUgZmlsdGVyKFR1bW9yVHlwZSA9PSAibmV1cm9ibGFzdG9tYSIpICU+JSBzZWxlY3QoUGF0aWVudElEKSAlPiUgdW5pcXVlICU+JSBucm93KClgKSBhbmQgYnJhaW4gdHVtb3Igc2FtcGxlcyAobiA9IGByIGNmRE5BdnNUaXNzdWUgJT4lIGZpbHRlcihUdW1vckdyb3VwID09ICJicmFpbiB0dW1vciIpICU+JSBzZWxlY3QoUGF0aWVudElEKSAlPiUgdW5pcXVlICU+JSBucm93KClgKS4gTW9yZSBkZXRhaWxlZCBzYW1wbGUgaW5mb3JtYXRpb24gaXMgc3VtbWFyaXplZCBpbiBzdXBwbGVtZW50YXJ5IHRhYmxlIFguIEZyb20gdGhlc2UgYHIgY2ZETkF2c1Rpc3N1ZSAlPiUgc2VsZWN0KFBhdGllbnRJRCkgJT4lIHVuaXF1ZSAlPiUgbnJvdygpYCBwYXRpZW50cywgY29weSBudW1iZXIgYWJlcnJhdGlvbnMgKENOQXMpIHdlcmUgbWVhc3VyZWQgaW4gcGxhc21hIHdpdGggc2hhbGxvdyB3aG9sZSBnZW5vbWUgc2VxdWVuY2luZyAoc1dHUykgaW4gYWxsIHNhbXBsZXMsIHdoaWxlIG9uIHRpc3N1ZSB0aGlzIHdhcyBkb25lIGVpdGhlciB3aXRoIHNXR1MgKG4gPSBgciBjZkROQXZzVGlzc3VlICU+JSBmaWx0ZXIodHVtb3JETkFfYXNzYXlfZGV0YWlsID09ICJzV0dTIikgJT4lIHNlbGVjdCh0dW1vckROQV9JRCkgJT4lIHVuaXF1ZSAlPiUgbnJvdygpYCksIFdFUyAobiA9IGByIGNmRE5BdnNUaXNzdWUgJT4lIGZpbHRlcih0dW1vckROQV9hc3NheV9kZXRhaWwgPT0gIldFUyIpICU+JSBzZWxlY3QodHVtb3JETkFfSUQpICU+JSB1bmlxdWUgJT4lIG5yb3coKWApIG9yIGFycmF5IENHSCAobiA9IGByIGNmRE5BdnNUaXNzdWUgJT4lIGZpbHRlcih0dW1vckROQV9hc3NheV9kZXRhaWwgIT0gInNXR1MiICYgdHVtb3JETkFfYXNzYXlfZGV0YWlsICE9ICJXRVMiICApICU+JSBzZWxlY3QoVW5pcXVlSUQpICU+JSB1bmlxdWUgJT4lIG5yb3coKWApLiBJbiBjYXNlIG9mIHNXR1MsIGByIHJvdW5kKChtYXBwZWRfcmVhZHMgJT4lIGZpbHRlcihiaW9tYXRlcmlhbCA9PSAiY2ZETkEiKSAlPiUgcHVsbChyYXdfdG90YWxfc2VxdWVuY2VzKSAlPiUgbWVkaWFuKCkpLzFlNiwyKWBNIFtgciAobWFwcGVkX3JlYWRzICU+JSBmaWx0ZXIoYmlvbWF0ZXJpYWwgPT0gImNmRE5BIikgJT4lIHB1bGwocmF3X3RvdGFsX3NlcXVlbmNlcykgJT4lIHF1YW50aWxlKCkpWzJdYC1gciAobWFwcGVkX3JlYWRzICU+JSBmaWx0ZXIoYmlvbWF0ZXJpYWwgPT0gImNmRE5BIikgJT4lIHB1bGwocmF3X3RvdGFsX3NlcXVlbmNlcykgJT4lIHF1YW50aWxlKCkpWzRdYF0gcmVhZHMgd2VyZSBnZW5lcmF0ZWQgZm9yIGNmRE5BIGFuZCBgciByb3VuZCgobWFwcGVkX3JlYWRzICU+JSBmaWx0ZXIoYmlvbWF0ZXJpYWwgPT0gInR1bW9yIEROQSIpICU+JSBwdWxsKHJhd190b3RhbF9zZXF1ZW5jZXMpICU+JSBtZWRpYW4oKSkvMWU2LDIpYE0gW2ByIChtYXBwZWRfcmVhZHMgJT4lIGZpbHRlcihiaW9tYXRlcmlhbCA9PSAidHVtb3IgRE5BIikgJT4lIHB1bGwocmF3X3RvdGFsX3NlcXVlbmNlcykgJT4lIHF1YW50aWxlKCkpWzJdYC1gciAobWFwcGVkX3JlYWRzICU+JSBmaWx0ZXIoYmlvbWF0ZXJpYWwgPT0gInR1bW9yIEROQSIpICU+JSBwdWxsKHJhd190b3RhbF9zZXF1ZW5jZXMpICU+JSBxdWFudGlsZSgpKVs0XWBdIGZvciB0aXNzdWUgRE5BLCB3aXRoIGByIHJvdW5kKChkdXBsaWNhdGVkX3JlYWRzICU+JSBmaWx0ZXIoYmlvbWF0ZXJpYWwgPT0gImNmRE5BIikgJT4lIHB1bGwoZHVwbGljYXRlX3BlcmNlbnRhZ2UpICU+JSBtZWRpYW4oKSksMilgJSBbYHIgKGR1cGxpY2F0ZWRfcmVhZHMgJT4lIGZpbHRlcihiaW9tYXRlcmlhbCA9PSAiY2ZETkEiKSAlPiUgcHVsbChkdXBsaWNhdGVfcGVyY2VudGFnZSkgJT4lIHF1YW50aWxlKCkpWzJdYC1gciAoZHVwbGljYXRlZF9yZWFkcyAlPiUgZmlsdGVyKGJpb21hdGVyaWFsID09ICJjZkROQSIpICU+JSBwdWxsKGR1cGxpY2F0ZV9wZXJjZW50YWdlKSAlPiUgcXVhbnRpbGUoKSlbNF1gXSBhbmQgYHIgcm91bmQoKGR1cGxpY2F0ZWRfcmVhZHMgJT4lIGZpbHRlcihiaW9tYXRlcmlhbCA9PSAidHVtb3IgRE5BIikgJT4lIHB1bGwoZHVwbGljYXRlX3BlcmNlbnRhZ2UpICU+JSBtZWRpYW4oKSksMilgJSBkdXBsaWNhdGUgcmVhZHMgW2ByIChkdXBsaWNhdGVkX3JlYWRzICU+JSBmaWx0ZXIoYmlvbWF0ZXJpYWwgPT0gInR1bW9yIEROQSIpICU+JSBwdWxsKGR1cGxpY2F0ZV9wZXJjZW50YWdlKSAlPiUgcXVhbnRpbGUoKSlbMl1gLWByIChkdXBsaWNhdGVkX3JlYWRzICU+JSBmaWx0ZXIoYmlvbWF0ZXJpYWwgPT0gInR1bW9yIEROQSIpICU+JSBwdWxsKGR1cGxpY2F0ZV9wZXJjZW50YWdlKSAlPiUgcXVhbnRpbGUoKSlbNF1gXSwgcmVzcGVjdGl2ZWx5LgoKCioqQ29weSBudW1iZXIgYWJub3JtYWxpdHkgaXMgaGlnaGVyIGluIHR1bW9yIHRpc3N1ZSB0aGFuIGluIHBsYXNtYS4qKiBGb3IgZXZlcnkgc2FtcGxlLCB0aGUgbW9kaWZpZWQgY29weSBudW1iZXIgcHJvZmlsZSBhYm5vcm1hbGl0eSAoQ1BBbSkgc2NvcmUgd2FzIGNhbGN1bGF0ZWQgKHNlZSBNZXRob2RzIGZvciBkZXRhaWxzLCBzZWUgZmlndXJlICMjMkEgYW5kICMjMkIgZm9yIGFuIGlsbHVzdHJhdGlvbiBvZiB0aGUgcmVsYXRpb25zaGlwIGJldHdlZW4gdGhlIGdlbm9tZS13aWRlIGNvcHkgbnVtYmVyIHByb2ZpbGUgYW5kIHRoZSBDUEFtIHNjb3JlKS4gVGhlIG1lZGlhbiBDUEFtIGFjcm9zcyBhbGwgdHVtb3IgdHlwZXMgd2FzIGZvdW5kIHRvIGJlIGByIG1lZGlhbihjZkROQXZzVGlzc3VlJGNwYV9jZkROQSlgIFtgciBxdWFudGlsZShjZkROQXZzVGlzc3VlJGNwYV9jZkROQSlbMl1gLWByIHF1YW50aWxlKGNmRE5BdnNUaXNzdWUkY3BhX2NmRE5BKVs0XWBdIGluIGNmRE5BIGFuZCBgciBtZWRpYW4oY2ZETkF2c1Rpc3N1ZSRjcGFfdHVtb3JETkEpYCBbYHIgcXVhbnRpbGUoY2ZETkF2c1Rpc3N1ZSRjcGFfdHVtb3JETkEpWzJdYC1gciBxdWFudGlsZShjZkROQXZzVGlzc3VlJGNwYV90dW1vckROQSlbNF1gXSAgaW4gdGlzc3VlIEROQSAoZmlndXJlICMjIzRCIGlsbHVzdHJhdGVzIHRoZSBDUEFtIHNjb3JlIHBlciB0dW1vciB0eXBlKS4gQmFzZWQgb24gbWFudWFsIGluc3BlY3Rpb24gKHRpc3N1ZSBETkEpIG9yIHRoZSBwcmV2aW91c2x5IGVzdGFibGlzaGVkIDElIEZEUiB0aHJlc2hvbGQgZm9yIENQQW0gKGNmRE5BLCBzZWUgTWV0aG9kcyksIHdlIGZvdW5kIHRoYXQgYHIgY2ZETkF2c1Rpc3N1ZSAlPiUgZmlsdGVyKENOQV9jZkROQSA9PSAiZmxhdCIpICU+JSBwdWxsKENOQV9jZkROQSkgJT4lIGxlbmd0aCgpYCAoYHIgMTAwKmNmRE5BdnNUaXNzdWUgJT4lIGZpbHRlcihDTkFfY2ZETkEgPT0gImZsYXQiKSAlPiUgcHVsbChDTkFfY2ZETkEpICU+JSBsZW5ndGgoKSAvIGNmRE5BdnNUaXNzdWUgJT4lIGZpbHRlcihDTkFfY2ZETkEgPT0gIkNOQSIgfCBDTkFfY2ZETkEgPT0gImZsYXQiICkgJT4lIHB1bGwoQ05BX2NmRE5BKSAlPiUgbGVuZ3RoKClgJSkgY2ZETkEgc2FtcGxlcyBhbmQgYHIgKGNmRE5BdnNUaXNzdWUgJT4lIGZpbHRlcih0dW1vckROQV9DTkFzX2NvbnNlbnN1cyA9PSAiRkFMU0UiKSAlPiUgcHVsbCh0dW1vckROQV9DTkFzX2NvbnNlbnN1cykgJT4lIGxlbmd0aCgpKWAgKGByICAxMDAqKGNmRE5BdnNUaXNzdWUgJT4lIGZpbHRlcih0dW1vckROQV9DTkFzX2NvbnNlbnN1cyA9PSAiRkFMU0UiKSAlPiUgcHVsbCh0dW1vckROQV9DTkFzX2NvbnNlbnN1cykgJT4lIGxlbmd0aCgpKSAvIChjZkROQXZzVGlzc3VlICU+JSBwdWxsKHR1bW9yRE5BX0NOQXNfY29uc2Vuc3VzKSAlPiUgbGVuZ3RoKCkpYCUpIHR1bW9yIHNhbXBsZXMgd2VyZSBsYWJlbGVkIGFzIOKAnGZsYXTigJ0sIGkuZS4sIGNvcHkgbnVtYmVyIG5ldXRyYWwuICAKCgoqKmNmRE5BIHNhbXBsZSBxdWFsaXR5IGFuZCBkaXNlYXNlIGV4dGVudCBkZXRlcm1pbmVzIGNvbmNvcmRhbmNlIGJldHdlZW4gY2ZETkEgYW5kIHRpc3N1ZSBETkEuKiogUHJldmlvdXMgc3R1ZGllcyBoYXZlIHBvaW50ZWQgYXQgYSBzdWJzdGFudGlhbCBpbmZsdWVuY2Ugb2YgY2ZETkEgc2FtcGxlIHF1YWxpdHkgb24gdGhlIGRldGVjdGlvbiBvZiB0dW1vci1kZXJpdmVkIEROQSBpbiBjZkROQSAoQUREIFJFRlMpLiBXZSBhc3Nlc3NlZCB0aGUgY2ZETkEgcXVhbGl0eSBieSBkZXRlcm1pbmluZyB0aGUgcmF0aW8gb2YgY2ZETkEgKDwgNzAwIGJwKSB2cy4gaGlnaCBtb2xlY3VsYXIgd2VpZ2h0ICg+IDcwMCBicCkgZm9yIGByIGNmRE5BdnNUaXNzdWUgJT4lIGZpbHRlcighaXMubmEoY2ZETkFfSE1XX3JhdGlvKSkgJT4lIG5yb3coKWAgc2FtcGxlcyAoYHIgbWVkaWFuKGNmRE5BdnNUaXNzdWUkY2ZETkFfSE1XX3JhdGlvLCBuYS5ybSA9IFRSVUUpYCBbYHIgcXVhbnRpbGUoY2ZETkF2c1Rpc3N1ZSRjZkROQV9ITVdfcmF0aW8sIG5hLnJtID0gVFJVRSlbMl1gLWByIHF1YW50aWxlKGNmRE5BdnNUaXNzdWUkY2ZETkFfSE1XX3JhdGlvLCBuYS5ybSA9IFRSVUUpWzRdYF0sIGZpZ3VyZSAjIzEgYW5kIHN1cHBsZW1lbnRhbCBmaWd1cmVzICNYWCkuIEZvciBldmVyeSBjZkROQS10aXNzdWUgcGFpciwgdGhlIFBlYXJzb24gUiBhbmQgdGhlIENQQW0gc2NvcmUgKHNlZSBNZXRob2RzKSB3YXMgY2FsY3VsYXRlZCBhbmQgYXNzb2NpYXRlZCB3aXRoIHRoZSBjZkROQS9ITVcgcmF0aW8gKGZpZ3VyZSBYWCwgc3VwcGxlbWVudGFsIGZpZ3VyZXMgWFgpLiAKPCEtLSBUaGUgbWVkaWFuIGNmRE5BL0hNVyByYXRpbyBvZiBjb3B5IG51bWJlciBuZXV0cmFsIGNmRE5BIHNhbXBsZXMgd2FzIGByIGNmRE5BdnNUaXNzdWUgJT4lIGZpbHRlcihDTkFfY2ZETkEgPT0gImZsYXQiKSAlPiUgcHVsbChjZkROQV9ITVdfcmF0aW8gKSAlPiUgbWVkaWFuKG5hLnJtID0gVFJVRSlgIFtgciBxdWFudGlsZShjZkROQXZzVGlzc3VlICU+JSBmaWx0ZXIoQ05BX2NmRE5BID09ICJmbGF0IikgJT4lIHB1bGwoY2ZETkFfSE1XX3JhdGlvICksIG5hLnJtID0gVFJVRSlbMl1gIC0gYHIgcXVhbnRpbGUoY2ZETkF2c1Rpc3N1ZSAlPiUgZmlsdGVyKENOQV9jZkROQSA9PSAiZmxhdCIpICU+JSBwdWxsKGNmRE5BX0hNV19yYXRpbyApLG5hLnJtID0gVFJVRSlbNF1gXSB2ZXJzdXMgYHIgY2ZETkF2c1Rpc3N1ZSAlPiUgZmlsdGVyKENOQV9jZkROQSA9PSAiQ05BIikgJT4lIHB1bGwoY2ZETkFfSE1XX3JhdGlvICkgJT4lIG1lZGlhbihuYS5ybSA9IFRSVUUpYCBbYHIgKGNmRE5BdnNUaXNzdWUgJT4lIGZpbHRlcihDTkFfY2ZETkEgPT0gIkNOQSIpICU+JSBwdWxsKGNmRE5BX0hNV19yYXRpbyApICU+JSBxdWFudGlsZShuYS5ybSA9IFRSVUUpKVsyXWAgLSBgciAoY2ZETkF2c1Rpc3N1ZSAlPiUgZmlsdGVyKENOQV9jZkROQSA9PSAiQ05BIikgJT4lIHB1bGwoY2ZETkFfSE1XX3JhdGlvICkgJT4lIHF1YW50aWxlKG5hLnJtID0gVFJVRSkpWzRdYF0gZm9yIHNhbXBsZXMgYWJvdmUgdGhlIDElIEZEUiB0aHJlc2hvbGQgKHAgPCBgciB3aWxjb3gudGVzdChjZkROQXZzVGlzc3VlICU+JSBmaWx0ZXIoQ05BX2NmRE5BID09ICJDTkEiKSAlPiUgcHVsbChjZkROQV9ITVdfcmF0aW8gKSwgY2ZETkF2c1Rpc3N1ZSAlPiUgZmlsdGVyKENOQV9jZkROQSA9PSAiZmxhdCIpICU+JSBwdWxsKGNmRE5BX0hNV19yYXRpbyApKVszXWAsIFdpbGNveG9uIFJhbmsgU3VtIHRlc3QpLiAgLS0+CkluIEZpZ3VyZSBYWCwgd2Ugb2JzZXJ2ZWQgYW4gYXBwYXJlbnQgaW5mbHVlbmNlIG9mIGNmRE5BL0hNVyByYXRpbyBhbmQgdGhlIHRpc3N1ZSBhc3NheSAoaS5lLiBJbGx1bWluYSBCZWFkQ2hpcCwgc1dHUywgV0VTKSBvbiB0aGUgY29weSBudW1iZXIgbG9hZCBpbiBjZkROQS4gU3Vic2VxdWVudGx5LCB3ZSBtb3JlIGRlZXBseSBpbnZlc3RpZ2F0ZWQgdGhlIGVmZmVjdCBvZiB0aGVzZSBwYXJhbWV0ZXJzIG9uIHRoZSBhZ3JlZW1lbnQgYmV0d2VlbiB0aGUgdGlzc3VlIENOQXMgYW5kIGNmRE5BIENOQXMuIFVzaW5nIGEgZ2VuZXJhbGl6ZWQgYWRkaXRpdmUgbW9kZWwgKEdBTSksIHdlIGZvdW5kIHRoYXQgYSBoaWdoZXIgY2ZETkEvSE1XIHJhdGlvIChhZnRlciBsb2cxMCB0cmFuc2Zvcm1hdGlvbikgd2FzIGFzc29jaWF0ZWQgd2l0aCBhIGJldHRlciBhZ3JlZW1lbnQgYmV0d2VlbiB0aXNzdWUgQ05BIGFuZCBjZkROQSBDTkFzIChwIDwgYHIgc3VtbWFyeShNb2RlbCkkcC5wdlsiTDJSX3R1bW9yRE5BOmNmRE5BX0hNV19yYXRpb19sb2cxMCJdICsgMC4wMDFgKSwgYWZ0ZXIgYWRqdXN0aW5nIGZvciB0dW1vciB0eXBlLCBkaXNlYXNlIGV4dGVudCBhbmQgdGhlIHBsYXRmb3JtIG9uIHdoaWNoIHRoZSB0aXNzdWUgY29weSBudW1iZXIgd2FzIGRldGVybWluZWQgKGUuZy4gc1dHUyBvciBJbGx1bWluYSBCZWFkQ2hpcCwgZnVsbCBtb2RlbCBpbiBzdXBwbGVtZW50YWwgZGF0YSBYKS4gQmFzZWQgb24gcHJldmlvdXNseS1kZWZpbmVkIHRocmVzaG9sZHMgKHJlZiBlcGlnZW5ldGljcyksIHdlIGZvdW5kIHRoYXQgb2Ygb24gYSB0b3RhbCBvZiBgciBjZkROQXZzVGlzc3VlICU+JSBmaWx0ZXIoIWlzLm5hKGNmRE5BX0hNV19yYXRpbykpICU+JSBzZWxlY3QoUGF0aWVudElEKSAlPiUgbnJvdygpYCBzYW1wbGVzLCB0aGUgYHIgY2ZETkF2c1Rpc3N1ZSAlPiUgZmlsdGVyKGNmRE5BX0hNV19yYXRpbyA8IDEpICU+JSBucm93KClgIHNhbXBsZXMgd2l0aCBhIGNmRE5BL0hNVyByYXRpbyBsb3dlciB0aGFuIDEgKGxvdyBxdWFsaXR5KSBjb250YWluZWQgYHIgY2ZETkF2c1Rpc3N1ZSAlPiUgZmlsdGVyKGNmRE5BX0hNV19yYXRpbyA8IDEpICU+JSBmaWx0ZXIoQ05BX2NmRE5BID09ICdmbGF0JykgJT4lIG5yb3coKWAgKGByIGNmRE5BdnNUaXNzdWUgJT4lIGZpbHRlcihjZkROQV9ITVdfcmF0aW8gPCAxKSAlPiUgZmlsdGVyKENOQV9jZkROQSA9PSAnZmxhdCcpICU+JSBucm93KCkgLyBjZkROQXZzVGlzc3VlICU+JSBmaWx0ZXIoY2ZETkFfSE1XX3JhdGlvIDwgMSkgJT4lIG5yb3coKSAqMTAwYCUpIGNvcHkgbnVtYmVyIG5ldXRyYWwgc2FtcGxlcyBpbiBjZkROQSB3aGlsZSBvZiB0aGVzZSBgciBjZkROQXZzVGlzc3VlICU+JSBmaWx0ZXIoY2ZETkFfSE1XX3JhdGlvIDwgMSkgJT4lIGZpbHRlcihDTkFfY2ZETkEgPT0gJ2ZsYXQnKSAlPiUgbnJvdygpYCBjZkROQSBuZXV0cmFsIHNhbXBsZXMsIHRoZXJlIHdlcmUgYHIgY2ZETkF2c1Rpc3N1ZSAlPiUgZmlsdGVyKGNmRE5BX0hNV19yYXRpbyA8IDEpICU+JSBmaWx0ZXIodHVtb3JETkFfQ05Bc19jb25zZW5zdXMgPT0gJ1RSVUUnKSAlPiUgbnJvdygpYCBzYW1wbGVzIHdpdGggQ05BcyBpbiB0aGUgdHVtb3IuIE9mIGByIGNmRE5BdnNUaXNzdWUgJT4lIGZpbHRlcihjZkROQV9ITVdfcmF0aW8gPj0gMSAmIGNmRE5BX0hNV19yYXRpbyA8IDUpICU+JSBucm93KClgIHNhbXBsZXMgd2l0aCBhIHJhdGlvIGJldHdlZW4gMSBhbmQgNSAoaW50ZXJtZWRpYXRlIHF1YWxpdHkpIGByIGNmRE5BdnNUaXNzdWUgJT4lIGZpbHRlcihjZkROQV9ITVdfcmF0aW8gPj0gMSAmIGNmRE5BX0hNV19yYXRpbyA8IDUpICU+JSBmaWx0ZXIoQ05BX2NmRE5BID09ICdmbGF0JykgJT4lIG5yb3coKWAgKGByIGNmRE5BdnNUaXNzdWUgJT4lIGZpbHRlcihjZkROQV9ITVdfcmF0aW8gPj0gMSAmIGNmRE5BX0hNV19yYXRpbyA8IDUpICU+JSBmaWx0ZXIoQ05BX2NmRE5BID09ICdmbGF0JykgJT4lIG5yb3coKSAvIGNmRE5BdnNUaXNzdWUgJT4lIGZpbHRlcihjZkROQV9ITVdfcmF0aW8gPj0gMSAmIGNmRE5BX0hNV19yYXRpbyA8IDUpICU+JSBucm93KCkgKjEwMGAlKSB3ZXJlIGNvcHkgbnVtYmVyIG5ldXRyYWwgKGFsbCBjb3JyZXNwb25kaW5nIHR1bW9yIHNhbXBsZXMgY29udGFpbmVkIENOQXMpLiBGaW5hbGx5LCBvZiBgciBjZkROQXZzVGlzc3VlICU+JSBmaWx0ZXIoY2ZETkFfSE1XX3JhdGlvID49IDUpICU+JSBucm93KClgIGNmRE5BIHNhbXBsZXMgd2l0aCBhIHJhdGlvIG1vcmUgdGhhbiA1IChoaWdoIHF1YWxpdHkpLCBgciBjZkROQXZzVGlzc3VlICU+JSBmaWx0ZXIoY2ZETkFfSE1XX3JhdGlvID49IDUpICU+JSBmaWx0ZXIoQ05BX2NmRE5BID09ICdmbGF0JykgJT4lIG5yb3coKWAgKGByIGNmRE5BdnNUaXNzdWUgJT4lIGZpbHRlcihjZkROQV9ITVdfcmF0aW8gPj0gNSkgJT4lIGZpbHRlcihDTkFfY2ZETkEgPT0gJ2ZsYXQnKSAlPiUgbnJvdygpIC8gY2ZETkF2c1Rpc3N1ZSAlPiUgZmlsdGVyKGNmRE5BX0hNV19yYXRpbyA+PSA1KSAlPiUgbnJvdygpICoxMDBgJSkgd2VyZSBjb3B5IG51bWJlciBuZXV0cmFsLiBVcG9uIGNsb3NlciBpbnNwZWN0aW9uIG9mIHRoZXNlIHRocmVlIGNhc2VzLCB0aGUgdHVtb3Igd2FzIGFsc28gY29weSBudW1iZXIgbmV1dHJhbCBpbiBvbmUgKHBhdGllbnQgMDA4KSBhbmQgY29udGFpbmVkIHNlZ21lbnRhbCBhYmVycmF0aW9ucyBpbiB0aGUgb3RoZXIgdHdvIGNhc2VzIChwYXRpZW50IDA0NCwgcGF0aWVudCAyMDYpLiBPdmVyYWxsLCBkaXNhZ3JlZW1lbnQgKGkuZS4gdGlzc3VlIEROQSBjb250YWluaW5nIENOQXMgd2hpbGUgdGhlIHBsYXNtYSBkb2VzIG5vdCBvciB2aWNlIHZlcnNhKSB3YXMgc2VlbiBpbiBgciBjZkROQXZzVGlzc3VlICU+JSBmaWx0ZXIodHVtb3JETkFfQ05Bc19jb25zZW5zdXMgPT0gIkZBTFNFIiAmIENOQV9jZkROQSA9PSAnQ05BJykgJT4lIG5yb3coKWAgc2FtcGxlcyBhbmQgYHIgY2ZETkF2c1Rpc3N1ZSAlPiUgZmlsdGVyKHR1bW9yRE5BX0NOQXNfY29uc2Vuc3VzID09ICJUUlVFIiAmIENOQV9jZkROQSA9PSAnZmxhdCcpICU+JSBucm93KClgIHNhbXBsZXMsIHJlc3BlY3RpdmVseS4gVGhlIGNmRE5BL0hNVyByYXRpbyBpbiB0aGVzZSBgciBjZkROQXZzVGlzc3VlICU+JSBmaWx0ZXIodHVtb3JETkFfQ05Bc19jb25zZW5zdXMgPT0gIkZBTFNFIiAmIENOQV9jZkROQSA9PSAnQ05BJykgJT4lIG5yb3coKSArIGNmRE5BdnNUaXNzdWUgJT4lIGZpbHRlcih0dW1vckROQV9DTkFzX2NvbnNlbnN1cyA9PSAiVFJVRSIgJiBDTkFfY2ZETkEgPT0gJ2ZsYXQnKSAlPiUgbnJvdygpYCBkaXNjb3JkYW50IHNhbXBsZXMgaXMgIGByIHJvdW5kKChjZkROQXZzVGlzc3VlICU+JSBmaWx0ZXIodHVtb3JETkFfQ05Bc19jb25zZW5zdXMgPT0gIlRSVUUiICYgQ05BX2NmRE5BID09ICdmbGF0JyB8IHR1bW9yRE5BX0NOQXNfY29uc2Vuc3VzID09ICJGQUxTRSIgJiBDTkFfY2ZETkEgPT0gJ0NOQScpICAlPiUgcHVsbChjZkROQV9ITVdfcmF0aW8pICU+JSBtZWRpYW4obmEucm0gPSBUUlVFKSksMilgIFtgciAoY2ZETkF2c1Rpc3N1ZSAlPiUgZmlsdGVyKHR1bW9yRE5BX0NOQXNfY29uc2Vuc3VzID09ICJUUlVFIiAmIENOQV9jZkROQSA9PSAnZmxhdCcgfCB0dW1vckROQV9DTkFzX2NvbnNlbnN1cyA9PSAiRkFMU0UiICYgQ05BX2NmRE5BID09ICdDTkEnKSAgJT4lIHB1bGwoY2ZETkFfSE1XX3JhdGlvKSAlPiUgcXVhbnRpbGUobmEucm0gPSBUUlVFKSlbMl1gLWByIChjZkROQXZzVGlzc3VlICU+JSBmaWx0ZXIodHVtb3JETkFfQ05Bc19jb25zZW5zdXMgPT0gIlRSVUUiICYgQ05BX2NmRE5BID09ICdmbGF0JyB8IHR1bW9yRE5BX0NOQXNfY29uc2Vuc3VzID09ICJGQUxTRSIgJiBDTkFfY2ZETkEgPT0gJ0NOQScpICAlPiUgcHVsbChjZkROQV9ITVdfcmF0aW8pICU+JSBxdWFudGlsZShuYS5ybSA9IFRSVUUpKVs0XWBdLCB3aGlsZSB0aGUgcmF0aW8gaW4gdGhlIGNvbmNvcmRhbnQgc2FtcGxlcyBpcyAgYHIgcm91bmQoKGNmRE5BdnNUaXNzdWUgJT4lIGZpbHRlcih0dW1vckROQV9DTkFzX2NvbnNlbnN1cyA9PSAiRkFMU0UiICYgQ05BX2NmRE5BID09ICdmbGF0JyB8IHR1bW9yRE5BX0NOQXNfY29uc2Vuc3VzID09ICJUUlVFIiAmIENOQV9jZkROQSA9PSAnQ05BJykgICU+JSBwdWxsKGNmRE5BX0hNV19yYXRpbykgJT4lIG1lZGlhbihuYS5ybSA9IFRSVUUpKSwyKWAgW2ByIChjZkROQXZzVGlzc3VlICU+JSBmaWx0ZXIodHVtb3JETkFfQ05Bc19jb25zZW5zdXMgPT0gIlRSVUUiICYgQ05BX2NmRE5BID09ICdDTkEnIHwgdHVtb3JETkFfQ05Bc19jb25zZW5zdXMgPT0gIkZBTFNFIiAmIENOQV9jZkROQSA9PSAnZmxhdCcpICAlPiUgcHVsbChjZkROQV9ITVdfcmF0aW8pICU+JSBxdWFudGlsZShuYS5ybSA9IFRSVUUpKVsyXWAtYHIgKGNmRE5BdnNUaXNzdWUgJT4lIGZpbHRlcih0dW1vckROQV9DTkFzX2NvbnNlbnN1cyA9PSAiRkFMU0UiICYgQ05BX2NmRE5BID09ICdmbGF0JyB8IHR1bW9yRE5BX0NOQXNfY29uc2Vuc3VzID09ICJUUlVFIiAmIENOQV9jZkROQSA9PSAnQ05BJykgICU+JSBwdWxsKGNmRE5BX0hNV19yYXRpbykgJT4lIHF1YW50aWxlKG5hLnJtID0gVFJVRSkpWzRdYF0uCkZ1cnRoZXJtb3JlLCBiYXNlZCBvbiB0aGUgR0FNLCBwYXRpZW50cyB3aXRoIG1ldGFzdGF0aWMgZGlzZWFzZSBoYWQgYSBoaWdoZXIgYWdyZWVtZW50cyBiZXR3ZWVuIHRoZSBsb2cyKHJhdGlvKSBpbiBjZkROQSBhbmQgbG9nMihyYXRpbykgaW4gdGlzc3VlIEROQS4gCgoqKlNwYXRpYWwgaGV0ZXJvZ2VuZWl0eSBpbiB0dW1vciBzYW1wbGVzLioqIEZvciB0d28gbmVwaHJvYmxhc3RvbWEgY2FzZXMsIGNmRE5BIHdhcyBhdmFpbGFibGUgYXQgZGlhZ25vc2lzIGFuZCB0dW1vciB0aXNzdWUgYWZ0ZXIgdHJlYXRtZW50IChwYXRpZW50IFhYIGFuZCBwYXRpZW50IFhYKS4gUGF0aWVudCBgciBzYW1wbGVfYW5ub3RhdGlvbiAlPiUgZmlsdGVyKHR1bW9yRE5BX0lEID09ICIyUzg4IikgJT4lIHB1bGwoUGF0aWVudElEKSAlPiUgZ3N1YigicGF0aWVudF8wIiwgIiIsIC4pYCBhbmQgYHIgc2FtcGxlX2Fubm90YXRpb24gJT4lIGZpbHRlcih0dW1vckROQV9JRCA9PSAiMkcwNyIpICU+JSBwdWxsKFBhdGllbnRJRCkgJT4lIGdzdWIoInBhdGllbnRfMCIsICIiLCAuKWAgd2VyZSB0cmVhdGVkIGFjY29yZGluZyB0byB0aGUgU0lPUCBXaWxtcyB0dW1vciBwcm90b2NvbCBmb3IgbmVwaHJvYmxhc3RvbWEgKEFERFMgUkVGUykuIFBsYXNtYSBmcm9tIHRoZXNlIHR3byBwYXRpZW50cyB3YXMgb2J0YWluZWQgYmVmb3JlIGluaXRpYXRpb24gb2YgY2hlbW90aGVyYXB5IGFuZCB0aXNzdWUgc2FtcGxlcyB3ZXJlIG9idGFpbmVkIGFmdGVyIDQgd2Vla3Mgb2YgbmVvYWRqdXZhbnQgY2hlbW90aGVyYXB5LiBBZnRlciByZXNlY3Rpb24sIHRoZSBjb3B5IG51bWJlciBwcm9maWxlIHdhcyBkZXRlcm1pbmVkIGluIHRocmVlIGRpZmZlcmVudCBsb2NhdGlvbnMgaW4gdGhlIHJlc2VjdGVkIGtpZG5leSBhbmQgY29tcGFyZWQgdG8gdGhlIHByZS10cmVhdG1lbnQgcGxhc21hIHNhbXBsZSAoZmlndXJlIFhYWDJDKSwgd2hpY2ggcmV2ZWFsZWQgc3Vic3RhbnRpYWwgaW50cmEtdHVtb3IgZGlmZmVyZW5jZSBhbmQgZGlzY29yZGFuY2Ugd2l0aCBjZkROQSAoZS5nLiBwYXRpZW50IGByIHNhbXBsZV9hbm5vdGF0aW9uICU+JSBmaWx0ZXIodHVtb3JETkFfSUQgPT0gIjJTODgiKSAlPiUgcHVsbChQYXRpZW50SUQpICU+JSBnc3ViKCJwYXRpZW50XzAiLCAiIiwgLilgLCBnYWluIG9uIGNocjEyLCBwYXRpZW50IGByIHNhbXBsZV9hbm5vdGF0aW9uICU+JSBmaWx0ZXIodHVtb3JETkFfSUQgPT0gIjJHMDciKSAlPiUgcHVsbChQYXRpZW50SUQpICU+JSBnc3ViKCJwYXRpZW50XzAiLCAiIiwgLilgIGJvdGggcHJlc2VudCBpbiBjZkROQSBidXQgbm90IGluIGFsbCB0dW1vciBzZWN0aW9ucywgZmlndXJlIDJDKS4gRm9yIHBhdGllbnQgYHIgc2FtcGxlX2Fubm90YXRpb24gJT4lIGZpbHRlcih0dW1vckROQV9JRCA9PSAiMlM4OCIpICU+JSBwdWxsKFBhdGllbnRJRCkgJT4lIGdzdWIoInBhdGllbnRfMCIsICIiLCAuKWAsIGhpc3RvbG9naWMgZXZhbHVhdGlvbiBmb3IgbG9jYXRpb25zIDEgYW5kIDIgd2FzIGRldGVybWluZWQgdG8gYmUgdHJpcGhhc2ljIG5lcGhyb2JsYXN0b21hIHdpdGggbmVjcm9zaXMgYW5kIGxvY2F0aW9uIDMgd2FzIGtpZG5leSB3aXRoIGJsYXN0ZW1hLiBGb3IgcGF0aWVudCBgciBzYW1wbGVfYW5ub3RhdGlvbiAlPiUgZmlsdGVyKHR1bW9yRE5BX0lEID09ICIyRzA3IikgJT4lIHB1bGwoUGF0aWVudElEKSAlPiUgZ3N1YigicGF0aWVudF8wIiwgIiIsIC4pYCwgbG9jYXRpb25zIDEgYW5kIDMgd2VyZSBkZXRlcm1pbmVkIHRvIGJlIHRyaXBoYXNpYyBuZXBocm9ibGFzdG9tYSB3aXRoIHJoYWJkb215b2JsYXN0aWMgZGlmZmVyZW50aWF0aW9uIGFuZCBsb2NhdGlvbiAyIHdhcyBuZWNyb3RpYyB0aXNzdWUuIEltcG9ydGFudGx5LCBnYWluIG9mIDFxLCBhIHByb2dub3N0aWMgYmlvbWFya2VyIGluIFdpbG1zIHR1bW9yIChodHRwczovL3B1Ym1lZC5uY2JpLm5sbS5uaWguZ292LzI3NDMyOTE1LyksIHdhcyBvbmx5IG9ic2VydmVkIGluIGxvY2F0aW9uIDEgb2YgcGF0aWVudCBgciBzYW1wbGVfYW5ub3RhdGlvbiAlPiUgZmlsdGVyKHR1bW9yRE5BX0lEID09ICIyUzg4IikgJT4lIHB1bGwoUGF0aWVudElEKSAlPiUgZ3N1YigicGF0aWVudF8wIiwgIiIsIC4pYCBhbmQgbG9jYXRpb24gMiBhbmQgMyBvZiBwYXRpZW50IGByIHNhbXBsZV9hbm5vdGF0aW9uICU+JSBmaWx0ZXIodHVtb3JETkFfSUQgPT0gIjJHMDciKSAlPiUgcHVsbChQYXRpZW50SUQpICU+JSBnc3ViKCJwYXRpZW50XzAiLCAiIiwgLilgLCB3aGlsZSBub3QgaW4gY2ZETkEgYXQgZGlhZ25vc2lzLgoKKipDTkFzIGNhbiBiZSB1bmlxdWUgZm9yIGNmRE5BIG9yIGZvciB0aXNzdWUgRE5BLioqIFNldmVyYWwgc2FtcGxlcywgb2YgbW9kZXJhdGUgdG8gaGlnaCBxdWFsaXR5IChjZkROQS9ITVcgcmF0aW8gYWJvdmUgMSkgYW5kIHdpdGggYSBoaWdoIENQQW0gKG1vcmUgdGhhbiAzIHRpbWVzIHRoZSBDUEFtIGF0IHRoZSAxJSBGRFIgdGhyZXNob2xkKSBpbiBjZkROQSB3ZXJlIG9ic2VydmVkIHRvIGhhdmUgYSBsb3cgUGVhcnNvbiBjb3JyZWxhdGlvbiBjb2VmZmljaWVudCB3aXRoIHRoZSByZXNwZWN0aXZlIHR1bW9yIENQQW0gdmFsdWUgKGUuZy4gcGF0aWVudCAwNzksIHBhdGllbnQgMjEyLCBwYXRpZW50IDA3NywgcGF0aWVudCAxOTYpLiBVcG9uIGNsb3NlciBpbnNwZWN0aW9uLCBzZXZlcmFsIGFiZXJyYXRpb25zIGFyZSBkaXNjb3JkYW50IGJldHdlZW4gcGxhc21hIGFuZCB0aXNzdWUgRE5BIChwYXRpZW50IDA3NywgcGF0aWVudCAwNzksIHBhdGllbnQgMTk2LCBmaWd1cmUgWFhYKS4gRnVydGhlcm1vcmUsIG90aGVyIGRpc2NvcmRhbnQgc2FtcGxlcyB3ZXJlIHNlZW4gdXBvbiBtYW51YWwgaW5zcGVjdGlvbiwgYWxiZWl0IHdpdGggc21hbGxlciBhbmQgbW9yZSBzdWJ0bGUgZGlmZmVyZW5jZXMuIEluIHRocmVlIG5ldXJvYmxhc3RvbWEgY2FzZXMgKHBhdGllbnQgMTg1LCAxMzYsIDEwOSkgcmVjdXJyZW50IHNlZ21lbnRhbCBDTkFzICgxcCBkZWxldGlvbiwgMnAgZ2FpbiwgMTFxIGRlbGV0aW9uIGFuZCAxN3EgZ2Fpbikgd2VyZSBtb3JlIGNsZWFybHkgcHJlc2VudCBpbiB0aGUgY2ZETkEgdGhhbiBpbiB0aGUgdGlzc3VlIEROQS4gSW4gb25lIGNhc2UgKHBhdGllbnQgMjEyKSwgb25seSB0aGUgYW1wbGlmaWNhdGlvbiBvZiBNWUNOIG9uIDJwMjQuMyBjb3VsZCBiZSBkZXRlY3RlZCBpbiB0aGUgdGlzc3VlIEROQSB3aGlsZSBhbmFseXNpcyBvZiB0aGUgY2ZETkEgc2FtcGxlcyBzaG93ZWQgdGhhdCBtYW55IG1vcmUgQ05BcyB3ZXJlIHByZXNlbnQgKGZpZ3VyZSBYWFgpLiBGb3Igc2V2ZXJhbCBuZXBocm9ibGFzdG9tYSBjYXNlcyAoZS5nLiBwYXRpZW50IDAzNSBhbmQgMDU2KSwgY2hyb21vc29tYWwgYWJlcnJhdGlvbnMgd2VyZSBpZGVudGlmaWVkIGluIHRoZSBjZkROQSBhbmQgbm90IGluIHRoZSB0aXNzdWUgRE5BLiAKCioqY2ZETkEgaXMgY29tcGxlbWVudGFyeSB0byB0aXNzdWUgRE5BIGluIHRoZSByaXNrIHN0cmF0aWZpY2F0aW9uIG9mIG5ldXJvYmxhc3RvbWEgYW5kIG5lcGhyb2JsYXN0b21hLioqIEFzICpNWUNOKiBhbXBsaWZpY2F0aW9uIGlzIGFuIGltcG9ydGFudCBwcm9nbm9zdGljIGJpb21hcmtlciBpbiBuZXVyb2JsYXN0b21hLCB3ZSBpbnZlc3RpZ2F0ZWQgYWdyZWVtZW50IGJldHdlZW4gKk1ZQ04qIGdhaW4vYW1wbGlmaWNhdGlvbiBiZXR3ZWVuIGNmRE5BIGFuZCB0aXNzdWUgRE5BLiBPbiBhbGwgc2FtcGxlcyAoaXJyZXNwZWN0aXZlIG9mIHRoZSBzYW1wbGUgcXVhbGl0eSkgKG4gPSBgciBNWUNOICU+JSBucm93KClgKSwgKk1ZQ04qIGNhbGxzIHdlcmUgc2ltaWxhciBpbiBjZkROQSBhbmQgdGlzc3VlIEROQSB3aXRob3V0IGFueSBkaXNjcmVwYW5jaWVzLiBJbiBuZXBocm9ibGFzdG9tYSwgcmVseWluZyBvbiBjZkROQSBmb3IgZGV0ZXJtaW5pbmcgdGhlIHByZXNlbmNlIG9mIDFxIGdhaW4sIGEgcHJvZ25vc3RpYyBtYXJrZXIgKEFERCBSRUYpLCBgciB0YWJsZShuZXBocl8xcSRnYWluXzFxX1dUX2NmRE5BLCBuZXBocl8xcSRnYWluXzFxX1dUX3R1bW9yKVsxLDJdYCBzYW1wbGVzIChuID0gYHIgbmVwaHJfMXEgJT4lIG5yb3coKWApIChvciBgciB0YWJsZShuZXBocl8xcV9oaWdocXVhbCRnYWluXzFxX1dUX2NmRE5BLCBuZXBocl8xcV9oaWdocXVhbCRnYWluXzFxX1dUX3R1bW9yKVsxLDJdYC9gciBuZXBocl8xcV9oaWdocXVhbCAlPiUgbnJvdygpYCB3aGVuIG9ubHkgaW5jbHVkaW5nIHRoZSBpbnRlcm1lZGlhdGUgdG8gaGlnaCBxdWFsaXR5IHNhbXBsZXMgd2l0aCBhIGNmRE5BL0hNVyByYXRpbyBhYm92ZSAxKSB3aXRoIDFxIGdhaW4gd291bGQgaGF2ZSBiZWVuIG1pc3NlZCwgd2hpbGUgb25seSByZWx5aW5nIG9uIHRpc3N1ZSBETkEgMXEgZ2FpbiB3b3VsZCBoYXZlIGJlZW4gbWlzc2VkIGluIGByIHRhYmxlKG5lcGhyXzFxJGdhaW5fMXFfV1RfY2ZETkEsIG5lcGhyXzFxJGdhaW5fMXFfV1RfdHVtb3IpWzIsMV1gIGNhc2VzLiAKCioqQ2VyZWJyb3NwaW5hbCBmbHVpZCBpcyBwcmVmZXJhYmxlIHRvIHBsYXNtYSBmb3IgbWVkdWxsb2JsYXN0b21hKiogRm9yIGJyYWluIHR1bW9ycywgaXQgaXMgZXhwZWN0ZWQgdGhhdCBoaWdoZXIgdGlzc3VlIEROQSBmcmFjdGlvbnMgd2lsbCBiZSBmb3VuZCBpbiBjZXJlYnJvc3BpbmFsIGZsdWlkIChDU0YpIHdoZW4gY29tcGFyZWQgdG8gIHBsYXNtYS4gV2UgYW5hbHl6ZWQgYHIgc2FtcGxlX2Fubm90YXRpb24gJT4lIGZpbHRlcihDRkRfYmlvbWF0ZXJpYWwgPT0gIkNTRiIpICU+JSBwdWxsKFBhdGllbnRJRCkgJT4lIHVuaXF1ZSgpICU+JSBsZW5ndGgoKWAgQ1NGIHNhbXBsZXMgb2YgYnJhaW4gdHVtb3IgcGF0aWVudHMuIEFsbCBzaG93ZWQgY2xlYXIgQ05BcyBpbiB0aGUgQ1NGIChhbG1vc3QpIGZ1bGx5IGNvbmNvcmRhbnQgdG8gdGhlIG1hdGNoaW5nIHRpc3N1ZSBETkEgcHJvZmlsZSAoSEVBVE1BUCBGSUdVUkUpLiBGb3IgcGF0aWVudCBYWFggd2l0aCBhIG1lZHVsbG9ibGFzdG9tYSwgd2UgaGFkIGEgbWF0Y2hpbmcgcGxhc21hIHNhbXBsZSBhdmFpbGFibGUsIHdpdGggYSBjZkROQS9ITVcgcmF0aW8gb2YgMS45NCwgLCB3aXRoIGEgY2ZETkEvSE1XIHJhdGlvIG9mIGByIGNmRE5BdnNUaXNzdWUgJT4lIGZpbHRlcihDRkRfSUQgPT0gIkNGRDE4MDIyOTEiKSAlPiUgcHVsbChjZkROQV9ITVdfcmF0aW8pYCB0aGF0IHByZXNlbnRlZCBhIGNvcHkgbnVtYmVyIG5ldXRyYWwgcHJvZmlsZSwgd2hpbGUgQ1NGIGRlcGljdGVkIGEgY2hyb21vc29tZSA2IGxvc3MgKHN1cHBsZW1lbnRhbCBmaWd1cmUgWFgpLgoK